Skip to content

Commit 621b48b

Browse files
committed
Upgrade supported-versions SVG generator to use VersionData and wrap into helper class.
1 parent d3e4978 commit 621b48b

3 files changed

Lines changed: 236 additions & 164 deletions

File tree

images/supported-versions.php

Lines changed: 10 additions & 162 deletions
Original file line numberDiff line numberDiff line change
@@ -1,167 +1,15 @@
11
<?php
2-
include_once __DIR__ . '/../include/prepend.inc';
3-
include_once __DIR__ . '/../include/branches.inc';
4-
5-
// Sizing constants.
6-
$margin_left = 80;
7-
$margin_right = 50;
8-
$header_height = 24;
9-
$year_width = 120;
10-
$branch_height = 30;
11-
$footer_height = 24;
12-
13-
function branches_to_show() {
14-
// Basically: show all 5.3+ branches with EOL dates > min_date().
15-
$branches = [];
16-
17-
// Flatten out the majors.
18-
foreach (get_all_branches() as $major_branches) {
19-
foreach ($major_branches as $branch => $version) {
20-
if (version_compare($branch, '5.3', 'ge') && get_branch_security_eol_date($branch) > min_date()) {
21-
$branches[$branch] = $version;
22-
}
23-
}
24-
}
25-
26-
ksort($branches);
27-
return $branches;
28-
}
29-
30-
function min_date(): DateTime
31-
{
32-
$now = new DateTime('January 1');
33-
return $now->sub(new DateInterval('P3Y'));
34-
}
35-
36-
function max_date(): DateTime
37-
{
38-
$now = new DateTime('January 1');
39-
return $now->add(new DateInterval('P5Y'));
40-
}
41-
42-
function date_horiz_coord(DateTime $date) {
43-
$diff = $date->diff(min_date());
44-
if (!$diff->invert) {
45-
return $GLOBALS['margin_left'];
46-
}
47-
return $GLOBALS['margin_left'] + ($diff->days / (365.24 / $GLOBALS['year_width']));
48-
}
49-
50-
$branches = branches_to_show();
51-
$i = 0;
52-
foreach ($branches as $branch => $version) {
53-
$branches[$branch]['top'] = $header_height + ($branch_height * $i++);
54-
}
55-
56-
if (!isset($non_standalone)) {
57-
header('Content-Type: image/svg+xml');
58-
echo '<?xml version="1.0"?>';
59-
}
60-
61-
$years = iterator_to_array(new DatePeriod(min_date(), new DateInterval('P1Y'), max_date()));
62-
$width = $margin_left + $margin_right + ((count($years) - 1) * $year_width);
63-
$height = $header_height + $footer_height + (count($branches) * $branch_height);
64-
?>
65-
<svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 <?php echo $width ?> <?php echo $height ?>" width="<?php echo $width ?>" height="<?php echo $height ?>">
66-
<style type="text/css">
67-
<![CDATA[
68-
@import url(/fonts/Fira/fira.css);
692

70-
text {
71-
fill: #333;
72-
font-family: var(--font-family-sans-serif);
73-
font-size: <?php echo (2 / 3) * $header_height; ?>px;
74-
}
3+
use phpweb\Releases\Util\SupportTimelineSvgGenerator;
754

76-
g.eol rect,
77-
.branches rect.eol {
78-
fill: #f33;
79-
}
80-
81-
g.eol text {
82-
fill: white;
83-
}
84-
85-
g.security rect,
86-
.branches rect.security {
87-
fill: #f93;
88-
}
89-
90-
g.stable rect,
91-
.branches rect.stable {
92-
fill: #9c9;
93-
}
94-
95-
.branch-labels text {
96-
dominant-baseline: central;
97-
text-anchor: middle;
98-
}
99-
100-
.today line {
101-
stroke: #333;
102-
stroke-dasharray: 7,7;
103-
stroke-width: 3px;
104-
}
105-
106-
.today text {
107-
fill: #333;
108-
text-anchor: middle;
109-
}
110-
111-
.years line {
112-
stroke: black;
113-
}
114-
115-
.years text {
116-
text-anchor: middle;
117-
}
118-
]]>
119-
</style>
120-
121-
<!-- Branch labels -->
122-
<g class="branch-labels">
123-
<?php foreach ($branches as $branch => $version): ?>
124-
<g class="<?php echo get_branch_support_state($branch) ?>">
125-
<rect x="0" y="<?php echo $version['top'] ?>" width="<?php echo 0.5 * $margin_left ?>" height="<?php echo $branch_height ?>" />
126-
<text x="<?php echo 0.25 * $margin_left ?>" y="<?php echo $version['top'] + (0.5 * $branch_height) ?>">
127-
<?php echo htmlspecialchars($branch) ?>
128-
</text>
129-
</g>
130-
<?php endforeach ?>
131-
</g>
132-
133-
<!-- Branch blocks -->
134-
<g class="branches">
135-
<?php foreach ($branches as $branch => $version): ?>
136-
<?php
137-
$x_release = date_horiz_coord(get_branch_release_date($branch));
138-
$x_bug = date_horiz_coord(get_branch_bug_eol_date($branch));
139-
$x_eol = date_horiz_coord(get_branch_security_eol_date($branch));
140-
?>
141-
<rect class="stable" x="<?php echo $x_release ?>" y="<?php echo $version['top'] ?>" width="<?php echo $x_bug - $x_release ?>" height="<?php echo $branch_height ?>" />
142-
<rect class="security" x="<?php echo $x_bug ?>" y="<?php echo $version['top'] ?>" width="<?php echo $x_eol - $x_bug ?>" height="<?php echo $branch_height ?>" />
143-
<?php endforeach ?>
144-
</g>
5+
include_once __DIR__ . '/../include/prepend.inc';
6+
include_once __DIR__ . '/../include/branches.inc';
1457

146-
<!-- Year lines -->
147-
<g class="years">
148-
<?php foreach ($years as $date): ?>
149-
<line x1="<?php echo date_horiz_coord($date) ?>" y1="<?php echo $header_height ?>" x2="<?php echo date_horiz_coord($date) ?>" y2="<?php echo $header_height + (count($branches) * $branch_height) ?>" />
150-
<text x="<?php echo date_horiz_coord($date) ?>" y="<?php echo 0.8 * $header_height; ?>">
151-
<?php echo $date->format('j M Y') ?>
152-
</text>
153-
<?php endforeach ?>
154-
</g>
1558

156-
<!-- Today -->
157-
<g class="today">
158-
<?php
159-
$now = new DateTime();
160-
$x = date_horiz_coord($now);
161-
?>
162-
<line x1="<?php echo $x ?>" y1="<?php echo $header_height ?>" x2="<?php echo $x ?>" y2="<?php echo $header_height + (count($branches) * $branch_height) ?>" />
163-
<text x="<?php echo $x ?>" y="<?php echo $header_height + (count($branches) * $branch_height) + (0.8 * $footer_height) ?>">
164-
<?php echo 'Today: ' . $now->format('j M Y') ?>
165-
</text>
166-
</g>
167-
</svg>
9+
header('Content-Type: image/svg+xml');
10+
echo '<?xml version="1.0"?>';
11+
echo SupportTimelineSvgGenerator::drawSvg(
12+
releases: SupportTimelineSvgGenerator::getDefaultReleasesToShow(),
13+
minDate: SupportTimelineSvgGenerator::getDefaultMinimumReleaseDate(),
14+
maxDate: SupportTimelineSvgGenerator::getDefaultMaximumReleaseDate(),
15+
);
Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
<?php
2+
3+
namespace phpweb\Releases\Util;
4+
5+
use DateInterval;
6+
use DatePeriod;
7+
use DateTimeImmutable;
8+
use phpweb\Releases\VersionData;
9+
use function array_filter;
10+
use function count;
11+
use function htmlspecialchars;
12+
use function iterator_to_array;
13+
use function ksort;
14+
use function version_compare;
15+
16+
class SupportTimelineSvgGenerator
17+
{
18+
private const string ONLY_SHOW_ABOVE_VER = '5.3';
19+
20+
/**
21+
* Gets the start of the X asis on the supported versions graph
22+
*/
23+
public static function getDefaultMinimumReleaseDate(): DateTimeImmutable
24+
{
25+
return new DateTimeImmutable('January 1')->sub(new DateInterval('P3Y'));
26+
}
27+
28+
/**
29+
* Gets the end of the X axis on the supported version graph
30+
*/
31+
public static function getDefaultMaximumReleaseDate(): DateTimeImmutable
32+
{
33+
return new DateTimeImmutable('January 1')->add(new DateInterval('P5Y'));
34+
}
35+
36+
/**
37+
* @return array<string, VersionData>
38+
*/
39+
public static function getDefaultReleasesToShow()
40+
{
41+
$minDate = self::getDefaultMinimumReleaseDate();
42+
$branches = array_filter(
43+
VersionData::all(),
44+
fn(VersionData $version) => version_compare($version->label, self::ONLY_SHOW_ABOVE_VER, 'ge')
45+
&& $version->securityEOL
46+
&& $version->securityEOL > $minDate,
47+
);
48+
49+
ksort($branches);
50+
51+
return $branches;
52+
}
53+
54+
/**
55+
* @param array<string, VersionData> $releases
56+
*/
57+
public static function drawSvg(
58+
array $releases,
59+
DateTimeImmutable $minDate,
60+
DateTimeImmutable $maxDate,
61+
int $rowHeight = 30,
62+
int $marginLeft = 80,
63+
int $marginRight = 50,
64+
int $yearWidth = 120,
65+
int $headerHeight = 24,
66+
int $footerHeight = 24,
67+
): string {
68+
$transformX = function (DateTimeImmutable $date) use ($marginLeft, $marginRight, $minDate, $yearWidth) {
69+
$diff = $date->diff($minDate);
70+
if (!$diff->invert) {
71+
return $marginLeft;
72+
}
73+
74+
return $marginLeft + ($diff->days / (365.24 / $yearWidth));
75+
};
76+
77+
/** @var array<string, int> $topCoordinatesByReleaseLabel */
78+
$topCoordinatesByReleaseLabel = [];
79+
$i = 0;
80+
foreach ($releases as $branch => $version) {
81+
$topCoordinatesByReleaseLabel[$branch] = $headerHeight + ($rowHeight * $i++);
82+
}
83+
84+
$years = iterator_to_array(
85+
new DatePeriod(start: $minDate, interval: new DateInterval('P1Y'), end: $maxDate),
86+
);
87+
88+
$imageWidth = $marginLeft + $marginRight + ((count($years) - 1) * $yearWidth);
89+
$imageHeight = $headerHeight + $footerHeight + (count($releases) * $rowHeight);
90+
91+
ob_start();
92+
?>
93+
<svg xmlns="http://www.w3.org/2000/svg"
94+
viewbox="0 0 <?= $imageWidth . ' ' . $imageHeight ?>"
95+
width="<?= $imageWidth ?>" height="<?= $imageHeight ?>"
96+
>
97+
<style type="text/css">
98+
<![CDATA[
99+
100+
@import url(/fonts/Fira/fira.css);
101+
102+
text {
103+
fill: #333;
104+
font-family: var(--font-family-sans-serif);
105+
font-size: <?php echo (2 / 3) * $headerHeight; ?>px;
106+
}
107+
108+
g.eol rect,
109+
.branches rect.eol {
110+
fill: #f33;
111+
}
112+
113+
g.eol text {
114+
fill: white;
115+
}
116+
117+
g.security rect,
118+
.branches rect.security {
119+
fill: #f93;
120+
}
121+
122+
g.stable rect,
123+
.branches rect.stable {
124+
fill: #9c9;
125+
}
126+
127+
.branch-labels text {
128+
dominant-baseline: central;
129+
text-anchor: middle;
130+
}
131+
132+
.today line {
133+
stroke: #333;
134+
stroke-dasharray: 7, 7;
135+
stroke-width: 3px;
136+
}
137+
138+
.today text {
139+
fill: #333;
140+
text-anchor: middle;
141+
}
142+
143+
.years line {
144+
stroke: black;
145+
}
146+
147+
.years text {
148+
text-anchor: middle;
149+
}
150+
151+
]]>
152+
</style>
153+
154+
<!-- Branch labels -->
155+
<g class="branch-labels">
156+
<?php foreach ($releases as $branch => $release) { ?>
157+
<g class="<?= safe($release->supportState->value) ?>">
158+
<rect x="0" y="<?= $topCoordinatesByReleaseLabel[$release->label] ?>" width="<?= 0.5 * $marginLeft ?>" height="<?= $rowHeight ?>"/>
159+
<text x="<?= 0.25 * $marginLeft ?>" y="<?= $topCoordinatesByReleaseLabel[$release->label] + (0.5 * $rowHeight) ?>">
160+
<?= htmlspecialchars($branch) ?>
161+
</text>
162+
</g>
163+
<?php } ?>
164+
</g>
165+
166+
<!-- Branch blocks -->
167+
<g class="branches">
168+
<?php foreach ($releases as $release) { ?>
169+
<?php
170+
$x_release = $transformX($release->releaseDate);
171+
$x_bug = $transformX($release->bugfixEOL);
172+
$x_eol = $transformX($release->securityEOL);
173+
$top = $topCoordinatesByReleaseLabel[$release->label];
174+
?>
175+
<rect class="stable" x="<?= $x_release ?>" y="<?= $top ?>"
176+
width="<?= $x_bug - $x_release ?>"
177+
height="<?= $rowHeight ?>"
178+
/>
179+
<rect class="security" x="<?= $x_bug ?>" y="<?= $top ?>"
180+
width="<?= ($x_eol - $x_bug) ?>"
181+
height="<?= $rowHeight ?>"
182+
/>
183+
<?php } ?>
184+
</g>
185+
186+
<!-- Year lines -->
187+
<g class="years">
188+
<?php foreach ($years as $date) { ?>
189+
<line x1="<?=$transformX($date) ?>"
190+
y1="<?= $headerHeight ?>"
191+
x2="<?= $transformX($date) ?>"
192+
y2="<?= $headerHeight + (count($releases) * $rowHeight) ?>"
193+
/>
194+
<text x="<?= $transformX($date) ?>"
195+
y="<?= 0.8 * $headerHeight; ?>">
196+
<?= $date->format('j M Y') ?>
197+
</text>
198+
<?php } ?>
199+
</g>
200+
201+
<!-- Today -->
202+
<g class="today">
203+
<?php
204+
$now = new DateTimeImmutable();
205+
$x = $transformX($now);
206+
?>
207+
<line x1="<?= $x ?>" y1="<?= $headerHeight ?>"
208+
x2="<?= $x ?>"
209+
y2="<?= $headerHeight + (count($releases) * $rowHeight) ?>"
210+
/>
211+
<text x="<?= $x ?>" y="<?= $headerHeight + (count($releases) * $rowHeight) + (0.8 * $footerHeight) ?>">
212+
<?= safe('Today: ' . $now->format('j M Y')) ?>
213+
</text>
214+
</g>
215+
</svg>
216+
217+
<?php
218+
return ob_get_clean();
219+
}
220+
}

0 commit comments

Comments
 (0)