Skip to content

Commit 0b87455

Browse files
authored
Add step line (#13)
1 parent 195d9de commit 0b87455

File tree

6 files changed

+347
-2
lines changed

6 files changed

+347
-2
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ Below are some examples of the types of charts you can create using this library
3131
![alt text](./examples/output/simple-curved-chart.svg)
3232
[View source](./examples/simple-curved-chart.php)
3333

34+
### Step line chart
35+
![alt text](./examples/output/simple-step-chart.svg)
36+
[View source](./examples/simple-step-chart.php)
37+
3438
### Simple bar chart
3539
![alt text](./examples/output/simple-bar-chart.svg)
3640
[View source](./examples/simple-bar-chart.php)
Lines changed: 20 additions & 0 deletions
Loading

examples/simple-step-chart.php

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
use Maantje\Charts\Chart;
4+
use Maantje\Charts\Line\Line;
5+
use Maantje\Charts\Line\Lines;
6+
use Maantje\Charts\Line\Point;
7+
8+
require '../vendor/autoload.php';
9+
10+
$chart = new Chart(
11+
series: [
12+
new Lines(
13+
lines: [
14+
new Line(
15+
points: [
16+
new Point(y: 15, x: 0),
17+
new Point(y: 25, x: 50),
18+
new Point(y: 20, x: 100),
19+
new Point(y: 45, x: 150),
20+
new Point(y: 35, x: 200),
21+
new Point(y: 65, x: 250),
22+
new Point(y: 55, x: 300),
23+
new Point(y: 85, x: 350),
24+
new Point(y: 75, x: 400),
25+
new Point(y: 110, x: 450),
26+
],
27+
size: 4,
28+
lineColor: 'purple',
29+
stepLine: true
30+
),
31+
]
32+
),
33+
],
34+
);
35+
36+
echo $chart->render();

src/Line/Line.php

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ public function __construct(
1717
public int $size = 5,
1818
public ?string $yAxis = null,
1919
public string $lineColor = 'black',
20-
public ?float $curve = null
20+
public ?float $curve = null,
21+
public bool $stepLine = false,
2122
) {}
2223

2324
public function render(Chart $chart): string
@@ -36,7 +37,9 @@ public function render(Chart $chart): string
3637
$pointsSvg .= $point->render($x, $y);
3738
}
3839

39-
$d = $this->generateSmoothPath($points, $this->curve);
40+
$d = $this->stepLine
41+
? $this->generateStepPath($points)
42+
: $this->generateSmoothPath($points, $this->curve);
4043

4144
return new Fragment([
4245
new Path(
@@ -90,4 +93,26 @@ public function generateSmoothPath(array $points, ?float $curveFactor = null): s
9093

9194
return $d;
9295
}
96+
97+
/**
98+
* @param array{float, float}[] $points
99+
*/
100+
public function generateStepPath(array $points): string
101+
{
102+
if (count($points) < 2) {
103+
return '';
104+
}
105+
106+
$d = "M {$points[0][0]},{$points[0][1]}";
107+
108+
for ($i = 1; $i < count($points); $i++) {
109+
$current = $points[$i];
110+
111+
$d .= " H {$current[0]}";
112+
113+
$d .= " V {$current[1]}";
114+
}
115+
116+
return $d;
117+
}
93118
}

tests/Unit/CurvedLineChartTest.php

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
2+
<?php
3+
4+
use Maantje\Charts\Chart;
5+
use Maantje\Charts\Line\Line;
6+
use Maantje\Charts\Line\Lines;
7+
use Maantje\Charts\Line\Point;
8+
9+
it('renders curved line chart', function () {
10+
$chart = new Chart(
11+
series: [
12+
new Lines(
13+
lines: [
14+
new Line(
15+
points: [
16+
new Point(y: 0, x: 0),
17+
new Point(y: 4, x: 100),
18+
new Point(y: 12, x: 200),
19+
new Point(y: 8, x: 300),
20+
],
21+
curve: 10,
22+
),
23+
new Line(
24+
points: [
25+
new Point(y: 4, x: 0),
26+
new Point(y: 12, x: 100),
27+
new Point(y: 24, x: 200),
28+
new Point(y: 7, x: 300),
29+
],
30+
lineColor: 'blue',
31+
curve: 10,
32+
),
33+
]
34+
),
35+
],
36+
);
37+
38+
expect(pretty($chart->render()))->toBe(<<<'SVG'
39+
<svg xmlns="http://www.w3.org/2000/svg" width="800" height="600">
40+
<rect x="0" y="0" width="800" height="600" fill="white" fill-opacity="1" stroke="none" stroke-width="0" rx="0" ry="0">
41+
<title/>
42+
</rect>
43+
<text x="45" y="555" font-family="arial" font-size="14" fill="black" stroke="none" stroke-width="0" text-anchor="end" dominant-baseline="alphabetic" alignment-baseline="auto">0</text>
44+
<text x="45" y="450" font-family="arial" font-size="14" fill="black" stroke="none" stroke-width="0" text-anchor="end" dominant-baseline="alphabetic" alignment-baseline="auto">5</text>
45+
<text x="45" y="345" font-family="arial" font-size="14" fill="black" stroke="none" stroke-width="0" text-anchor="end" dominant-baseline="alphabetic" alignment-baseline="auto">10</text>
46+
<text x="45" y="240" font-family="arial" font-size="14" fill="black" stroke="none" stroke-width="0" text-anchor="end" dominant-baseline="alphabetic" alignment-baseline="auto">14</text>
47+
<text x="45" y="135" font-family="arial" font-size="14" fill="black" stroke="none" stroke-width="0" text-anchor="end" dominant-baseline="alphabetic" alignment-baseline="auto">19</text>
48+
<text x="45" y="30" font-family="arial" font-size="14" fill="black" stroke="none" stroke-width="0" text-anchor="end" dominant-baseline="alphabetic" alignment-baseline="auto">24</text>
49+
<text x="20" y="262.5" font-family="arial" font-size="14" fill="black" stroke="none" stroke-width="0" text-anchor="middle" dominant-baseline="alphabetic" alignment-baseline="middle" transform="rotate(270, 20, 262.5)"/>
50+
<line x1="55" y1="550" x2="770" y2="550" stroke="black" stroke-dasharray="none" stroke-width="1"/>
51+
<text x="55" y="575" font-family="arial" font-size="14" fill="black" stroke="none" stroke-width="0" text-anchor="middle" dominant-baseline="alphabetic" alignment-baseline="auto">0</text>
52+
<line x1="55" y1="550" x2="55" y2="545" stroke="black" stroke-dasharray="none" stroke-width="1"/>
53+
<text x="293.33333333333" y="575" font-family="arial" font-size="14" fill="black" stroke="none" stroke-width="0" text-anchor="middle" dominant-baseline="alphabetic" alignment-baseline="auto">100</text>
54+
<line x1="293.33333333333" y1="550" x2="293.33333333333" y2="545" stroke="black" stroke-dasharray="none" stroke-width="1"/>
55+
<text x="531.66666666667" y="575" font-family="arial" font-size="14" fill="black" stroke="none" stroke-width="0" text-anchor="middle" dominant-baseline="alphabetic" alignment-baseline="auto">200</text>
56+
<line x1="531.66666666667" y1="550" x2="531.66666666667" y2="545" stroke="black" stroke-dasharray="none" stroke-width="1"/>
57+
<text x="770" y="575" font-family="arial" font-size="14" fill="black" stroke="none" stroke-width="0" text-anchor="middle" dominant-baseline="alphabetic" alignment-baseline="auto">300</text>
58+
<line x1="770" y1="550" x2="770" y2="545" stroke="black" stroke-dasharray="none" stroke-width="1"/>
59+
<text x="412.5" y="590" font-family="arial" font-size="14" fill="black" stroke="none" stroke-width="0" text-anchor="middle" dominant-baseline="alphabetic" alignment-baseline="auto"/>
60+
<line x1="55" y1="550" x2="770" y2="550" stroke="#ccc" stroke-dasharray="none" stroke-width="1"/>
61+
<line x1="55" y1="445" x2="770" y2="445" stroke="#ccc" stroke-dasharray="none" stroke-width="1"/>
62+
<line x1="55" y1="340" x2="770" y2="340" stroke="#ccc" stroke-dasharray="none" stroke-width="1"/>
63+
<line x1="55" y1="235" x2="770" y2="235" stroke="#ccc" stroke-dasharray="none" stroke-width="1"/>
64+
<line x1="55" y1="130" x2="770" y2="130" stroke="#ccc" stroke-dasharray="none" stroke-width="1"/>
65+
<line x1="55" y1="25" x2="770" y2="25" stroke="#ccc" stroke-dasharray="none" stroke-width="1"/>
66+
<path d="M 55,550 C 78.83,541.25 245.67,488.75 293.33,462.50 C 341.00,436.25 484.00,296.25 531.67,287.50 C 579.33,278.75 746.17,366.25 770.00,375.00" fill="none" stroke="black" stroke-width="5"/>
67+
<circle cx="55" cy="550" r="10" fill="rgba(0, 0, 0, 0)" stroke="none" stroke-width="0">
68+
<title>0</title>
69+
</circle>
70+
<circle cx="293.33333333333" cy="462.5" r="10" fill="rgba(0, 0, 0, 0)" stroke="none" stroke-width="0">
71+
<title>4</title>
72+
</circle>
73+
<circle cx="531.66666666667" cy="287.5" r="10" fill="rgba(0, 0, 0, 0)" stroke="none" stroke-width="0">
74+
<title>12</title>
75+
</circle>
76+
<circle cx="770" cy="375" r="10" fill="rgba(0, 0, 0, 0)" stroke="none" stroke-width="0">
77+
<title>8</title>
78+
</circle>
79+
<path d="M 55,462.5 C 78.83,445.00 245.67,331.25 293.33,287.50 C 341.00,243.75 484.00,14.06 531.67,25.00 C 579.33,35.94 746.17,359.69 770.00,396.88" fill="none" stroke="blue" stroke-width="5"/>
80+
<circle cx="55" cy="462.5" r="10" fill="rgba(0, 0, 0, 0)" stroke="none" stroke-width="0">
81+
<title>4</title>
82+
</circle>
83+
<circle cx="293.33333333333" cy="287.5" r="10" fill="rgba(0, 0, 0, 0)" stroke="none" stroke-width="0">
84+
<title>12</title>
85+
</circle>
86+
<circle cx="531.66666666667" cy="25" r="10" fill="rgba(0, 0, 0, 0)" stroke="none" stroke-width="0">
87+
<title>24</title>
88+
</circle>
89+
<circle cx="770" cy="396.875" r="10" fill="rgba(0, 0, 0, 0)" stroke="none" stroke-width="0">
90+
<title>7</title>
91+
</circle>
92+
</svg>
93+
SVG
94+
);
95+
});
96+
97+
it('renders empty line chart', function () {
98+
$chart = new Chart(
99+
series: [
100+
new Lines(
101+
lines: []
102+
),
103+
],
104+
);
105+
106+
$svg = <<<'SVG'
107+
<svg xmlns="http://www.w3.org/2000/svg" width="800" height="600">
108+
<rect x="0" y="0" width="800" height="600" fill="white" fill-opacity="1" stroke="none" stroke-width="0" rx="0" ry="0">
109+
<title/>
110+
</rect>
111+
<text x="40" y="555" font-family="arial" font-size="14" fill="black" stroke="none" stroke-width="0" text-anchor="end" dominant-baseline="alphabetic" alignment-baseline="auto">0</text>
112+
<text x="40" y="450" font-family="arial" font-size="14" fill="black" stroke="none" stroke-width="0" text-anchor="end" dominant-baseline="alphabetic" alignment-baseline="auto">0</text>
113+
<text x="40" y="345" font-family="arial" font-size="14" fill="black" stroke="none" stroke-width="0" text-anchor="end" dominant-baseline="alphabetic" alignment-baseline="auto">0</text>
114+
<text x="40" y="240" font-family="arial" font-size="14" fill="black" stroke="none" stroke-width="0" text-anchor="end" dominant-baseline="alphabetic" alignment-baseline="auto">0</text>
115+
<text x="40" y="135" font-family="arial" font-size="14" fill="black" stroke="none" stroke-width="0" text-anchor="end" dominant-baseline="alphabetic" alignment-baseline="auto">0</text>
116+
<text x="40" y="30" font-family="arial" font-size="14" fill="black" stroke="none" stroke-width="0" text-anchor="end" dominant-baseline="alphabetic" alignment-baseline="auto">0</text>
117+
<text x="20" y="262.5" font-family="arial" font-size="14" fill="black" stroke="none" stroke-width="0" text-anchor="middle" dominant-baseline="alphabetic" alignment-baseline="middle" transform="rotate(270, 20, 262.5)"/>
118+
<line x1="50" y1="550" x2="770" y2="550" stroke="black" stroke-dasharray="none" stroke-width="1"/>
119+
<text x="410" y="590" font-family="arial" font-size="14" fill="black" stroke="none" stroke-width="0" text-anchor="middle" dominant-baseline="alphabetic" alignment-baseline="auto"/>
120+
<line x1="50" y1="550" x2="770" y2="550" stroke="#ccc" stroke-dasharray="none" stroke-width="1"/>
121+
<line x1="50" y1="445" x2="770" y2="445" stroke="#ccc" stroke-dasharray="none" stroke-width="1"/>
122+
<line x1="50" y1="340" x2="770" y2="340" stroke="#ccc" stroke-dasharray="none" stroke-width="1"/>
123+
<line x1="50" y1="235" x2="770" y2="235" stroke="#ccc" stroke-dasharray="none" stroke-width="1"/>
124+
<line x1="50" y1="130" x2="770" y2="130" stroke="#ccc" stroke-dasharray="none" stroke-width="1"/>
125+
<line x1="50" y1="25" x2="770" y2="25" stroke="#ccc" stroke-dasharray="none" stroke-width="1"/>
126+
</svg>
127+
SVG;
128+
129+
expect(pretty($chart->render()))->toBe($svg);
130+
});

0 commit comments

Comments
 (0)