Skip to content

Commit 6ae8f9f

Browse files
encukounedbat
authored andcommitted
Clean up the path code
1 parent 213f5fc commit 6ae8f9f

File tree

2 files changed

+83
-96
lines changed

2 files changed

+83
-96
lines changed

_tools/generate_release_cycle.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,8 @@ def write_svg(self, today: str, out_path: str) -> None:
125125
# CSS.
126126
# (Ideally we'd actually use `em` units, but SVG viewBox doesn't take
127127
# those.)
128+
129+
# Uppercase sizes are un-scaled
128130
SCALE = 18
129131

130132
# Width of the drawing and main parts
@@ -145,7 +147,7 @@ def date_to_x(date: dt.date) -> float:
145147
total_days = (last_date - first_date).days
146148
ratio = num_days / total_days
147149
x = ratio * (DIAGRAM_WIDTH - LEGEND_WIDTH - RIGHT_MARGIN)
148-
return x + LEGEND_WIDTH
150+
return (x + LEGEND_WIDTH) * SCALE
149151

150152
def year_to_x(year: int) -> float:
151153
"""Convert year number to an SVG X coordinate of 1st January"""
@@ -158,12 +160,12 @@ def format_year(year: int) -> str:
158160
with open(out_path, "w", encoding="UTF-8", newline="\n") as f:
159161
template.stream(
160162
SCALE=SCALE,
161-
diagram_width=DIAGRAM_WIDTH,
162-
diagram_height=(self.sorted_versions[0]["y"] + 2) * LINE_HEIGHT,
163+
diagram_width=DIAGRAM_WIDTH * SCALE,
164+
diagram_height=(self.sorted_versions[0]["y"] + 2) * LINE_HEIGHT * SCALE,
163165
years=range(first_date.year, last_date.year + 1),
164-
LINE_HEIGHT=LINE_HEIGHT,
165-
LEGEND_WIDTH=LEGEND_WIDTH,
166-
RIGHT_MARGIN=RIGHT_MARGIN,
166+
line_height=LINE_HEIGHT * SCALE,
167+
legend_width=LEGEND_WIDTH * SCALE,
168+
right_margin=RIGHT_MARGIN * SCALE,
167169
versions=list(reversed(self.sorted_versions)),
168170
today=dt.datetime.strptime(today, "%Y-%m-%d").date(),
169171
year_to_x=year_to_x,

_tools/release_cycle_template.svg.jinja

Lines changed: 75 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<svg
33
xmlns="http://www.w3.org/2000/svg"
44
class="release-cycle-chart"
5-
viewBox="0 0 {{ diagram_width * SCALE }} {{ diagram_height * SCALE }}"
5+
viewBox="0 0 {{ diagram_width }} {{ diagram_height }}"
66
>
77
<defs>
88
<linearGradient id="release-cycle-mask-gradient-{{ id_key }}">
@@ -12,25 +12,25 @@
1212
</defs>
1313

1414
{% for version in versions %}
15-
{% set y = version.y * LINE_HEIGHT %}
15+
{% set y = version.y * line_height %}
1616

1717
{% if version.y % 2 %}
1818
<!-- Row shading -->
1919
<rect
2020
class="release-cycle-row-shade"
2121
x="0em"
22-
y="{{ (y - 1.125) * SCALE }}"
23-
width="{{ diagram_width * SCALE }}"
24-
height="{{ LINE_HEIGHT * SCALE }}"
22+
y="{{ y - 1.125 * SCALE }}"
23+
width="{{ diagram_width }}"
24+
height="{{ line_height }}"
2525
/>
2626
{% endif %}
2727
{% endfor %}
2828

2929
{% for year in years %}
3030
<text
3131
class="release-cycle-year-text"
32-
x="{{ (year_to_x(year) + year_to_x(year + 1)) / 2 * SCALE }}"
33-
y="{{ (diagram_height - LINE_HEIGHT) * SCALE }}"
32+
x="{{ (year_to_x(year) + year_to_x(year + 1)) / 2 }}"
33+
y="{{ diagram_height - line_height }}"
3434
font-size="{{ SCALE * 0.75 }}"
3535
text-anchor="middle"
3636
>
@@ -39,10 +39,10 @@
3939
{% if not loop.last %}
4040
<line
4141
class="release-cycle-year-line"
42-
x1="{{ year_to_x(year + 1) * SCALE }}"
43-
x2="{{ year_to_x(year + 1) * SCALE }}"
42+
x1="{{ year_to_x(year + 1) }}"
43+
x2="{{ year_to_x(year + 1) }}"
4444
y1="0"
45-
y2="{{ (diagram_height - LINE_HEIGHT) * SCALE }}"
45+
y2="{{ diagram_height - line_height }}"
4646
font-size="{{ SCALE }}"
4747
/>
4848
{% endif %}
@@ -53,142 +53,127 @@
5353
<rect
5454
x="0"
5555
y="0"
56-
width="{{ LEGEND_WIDTH * SCALE }}"
57-
height="{{ diagram_height * SCALE }}"
56+
width="{{ legend_width }}"
57+
height="{{ diagram_height }}"
5858
fill="black"
5959
/>
6060
<rect
61-
x="{{ (LEGEND_WIDTH - RIGHT_MARGIN) * SCALE }}"
61+
x="{{ legend_width - right_margin }}"
6262
y="0"
63-
width="{{ RIGHT_MARGIN * SCALE }}"
64-
height="{{ diagram_height * SCALE }}"
63+
width="{{ right_margin }}"
64+
height="{{ diagram_height }}"
6565
fill="url(#release-cycle-mask-gradient-{{ id_key }})"
6666
/>
6767
<rect
68-
x="{{ (LEGEND_WIDTH ) * SCALE }}"
68+
x="{{ legend_width }}"
6969
y="0"
70-
width="{{ diagram_width * SCALE }}"
71-
height="{{ diagram_height * SCALE }}"
70+
width="{{ diagram_width }}"
71+
height="{{ diagram_height }}"
7272
fill="white"
7373
/>
7474
</mask>
7575

7676
{% for version in versions %}
77-
{% set y = version.y * LINE_HEIGHT %}
77+
{% set top_y = version.y * line_height - 1 * SCALE %}
78+
{% set small_text_y = version.y * line_height - 0.1 * SCALE %}
79+
80+
<!-- Colourful blob with a label. -->
7881

79-
<!-- Colourful blob with a label -->
8082
{% set start_x = date_to_x(version.first_release_date) %}
8183
{% set end_x = date_to_x(version.end_of_life_date) %}
8284

83-
<!-- bugfix status needs a security tail.
85+
<!-- bugfix/security blobs need to be split between the two phases.
8486
Draw the rectangle with two path elements instead.
85-
Thanks Claude.ai for the conversion.
87+
Thanks Claude.ai for the initial conversion.
8688
-->
87-
{% set half_x = [end_x, date_to_x(version.start_security_date)]|min %}
89+
{% set middle_x = ([end_x, date_to_x(version.start_security_date)]|min) %}
8890
{% set height = 1.25 * SCALE %}
89-
{% set left_width = (half_x - start_x) * SCALE %}
90-
{% set right_width = (end_x - half_x) * SCALE %}
91-
{% set left_x = start_x * SCALE %}
92-
{% set middle_x = half_x * SCALE %}
93-
{% set right_x = half_x * SCALE %}
94-
{% set rect_y = (y - 1) * SCALE %}
95-
{% set radius_value = 0.25 * SCALE %}
91+
{% set left_width = (middle_x - start_x) %}
92+
{% set right_width = (end_x - middle_x) %}
93+
{% set radius = 0.25 * SCALE %}
9694

9795
{% if version.status != "end-of-life" %}
98-
<!-- Split the blob -->
96+
<!-- Split the blob using path operations
97+
(Move-to, Vertical/Horizontal, Arc, Z=close shape;
98+
lowercase means relative to the last point.)
99+
We start drawing from the top of the straight boundary
100+
between the half-blobs.
101+
-->
99102
<path
100103
class="release-cycle-blob release-cycle-status-bugfix"
101104
d="
102-
M{{ left_x + radius_value }},{{ rect_y }}
103-
q{{ -radius_value }},0 {{ -radius_value }},{{ radius_value }}
104-
v{{ height - 2*radius_value }}
105-
q0,{{ radius_value }} {{ radius_value }},{{ radius_value }}
106-
H{{ middle_x }}
107-
V{{ rect_y }}
108-
Z
105+
M{{ middle_x }},{{ top_y }} {#- start -#}
106+
v{{ height }} {#- down -#}
107+
H{{ start_x + radius }} {#- left -#}
108+
a{{ radius }},{{ radius }} 90 0 1 {#- rounded corner -#}
109+
{{ -radius }} {{ -radius }}
110+
v{{ -height + 2*radius }} {#- up -#}
111+
a{{ radius }},{{ radius }} 90 0 1 {#- rounded corner -#}
112+
{{ radius }} {{ -radius }}
113+
Z {#- right -#}
109114
"
110115
/>
111116
<path
112117
class="release-cycle-blob release-cycle-status-security"
113118
d="
114-
M{{ right_x }},{{ rect_y }}
115-
h{{ right_width - radius_value }}
116-
q{{ radius_value }},0 {{ radius_value }},{{ radius_value }}
117-
v{{ height - 2*radius_value }}
118-
q0,{{ radius_value }} {{ -radius_value }},{{ radius_value }}
119-
H{{ middle_x }}
120-
V{{ rect_y }}
121-
Z
119+
M{{ middle_x }},{{ top_y }} {#- start -#}
120+
v{{ height }} {#- down -#}
121+
H{{ end_x - radius }} {#- right -#}
122+
a{{ radius }},{{ radius }} 90 0 0 {#- rounded corner -#}
123+
{{ radius }} {{ -radius }}
124+
v{{ -height + 2*radius }} {#- up -#}
125+
a{{ radius }},{{ radius }} 90 0 0 {#- rounded corner -#}
126+
{{ -radius }} {{ -radius }}
127+
Z {#- left -#}
122128
"
123129
/>
124130
{% endif %}
125131
<rect
126132
class="release-cycle-shade release-cycle-status-{{ version.status }}"
127-
x="{{ start_x * SCALE }}"
128-
y="{{ (y - 1) * SCALE }}"
129-
width="{{ (end_x - start_x) * SCALE }}"
133+
x="{{ start_x }}"
134+
y="{{ top_y }}"
135+
width="{{ (end_x - start_x) }}"
130136
height="{{ height }}"
131137
rx="0.25em"
132138
ry="0.25em"
133139
mask="url(#release-cycle-mask-{{ id_key }})"
134140
/>
135141
<rect
136142
class="release-cycle-border release-cycle-status-{{ version.status }}"
137-
x="{{ start_x * SCALE }}"
138-
y="{{ (y - 1) * SCALE }}"
139-
width="{{ (end_x - start_x) * SCALE }}"
143+
x="{{ start_x }}"
144+
y="{{ top_y }}"
145+
width="{{ (end_x - start_x) }}"
140146
height="{{ height }}"
141147
rx="0.25em"
142148
ry="0.25em"
143149
mask="url(#release-cycle-mask-{{ id_key }})"
144150
/>
145-
{% if version.status == "bugfix" %}
146-
<text
147-
class="release-cycle-blob-label release-cycle-status-bugfix"
148-
x="{{ (start_x + half_x) / 2 * SCALE }}"
149-
y="{{ (y - 0.1) * SCALE }}"
150-
font-size="{{ SCALE * 0.75 }}"
151+
<text
152+
class="release-cycle-blob-label release-cycle-status-{{ version.status }}"
153+
font-size="{{ SCALE * 0.75 }}"
154+
y="{{ small_text_y }}"
155+
{% if version.status == "bugfix" %}
156+
x="{{ (start_x + middle_x) / 2 }}"
151157
text-anchor="middle"
152-
>
153-
bugfix
154-
</text>
155-
{% elif version.status == "security" %}
156-
<text
157-
class="release-cycle-blob-label release-cycle-status-security"
158-
x="{{ (half_x + end_x) / 2 * SCALE }}"
159-
y="{{ (y - 0.1) * SCALE }}"
160-
font-size="{{ SCALE * 0.75 }}"
158+
{% elif version.status == "security" %}
159+
x="{{ (middle_x + end_x) / 2 }}"
161160
text-anchor="middle"
162-
>
163-
security
164-
</text>
165-
{% elif version.status == "end-of-life" %}
166-
<text
167-
class="release-cycle-blob-label release-cycle-status-end-of-life"
168-
x="{{ (end_x + 0.25) * SCALE }}"
161+
{% elif version.status == "end-of-life" %}
162+
x="{{ end_x + (0.25 * SCALE) }}"
169163
text-anchor="start"
170-
y="{{ (y - 0.1) * SCALE }}"
171-
font-size="{{ SCALE * 0.75 }}"
172-
>
173-
end-of-life
174-
</text>
175-
{% else %}
176-
<text
177-
class="release-cycle-blob-label release-cycle-status-feature"
178-
x="{{ (start_x - 0.5) * SCALE }}"
179-
y="{{ (y - 0.1) * SCALE }}"
180-
font-size="{{ SCALE * 0.75 }}"
164+
{% else %}
165+
x="{{ start_x - (0.5 * SCALE) }}"
181166
text-anchor="end"
167+
{% endif %}
182168
>
183169
{{ version.status }}
184170
</text>
185-
{% endif %}
186171

187172
<!-- Legend on the left -->
188173
<text
189174
class="release-cycle-version-label"
190175
x="{{ 0.5 * SCALE }}"
191-
y="{{ y * SCALE }}"
176+
y="{{ version.y * line_height }}"
192177
font-size="{{ SCALE }}"
193178
>
194179
Python {{ version.key }}
@@ -198,10 +183,10 @@
198183
<!-- A line for today -->
199184
<line
200185
class="release-cycle-today-line"
201-
x1="{{ date_to_x(today) * SCALE }}"
202-
x2="{{ date_to_x(today) * SCALE }}"
186+
x1="{{ date_to_x(today) }}"
187+
x2="{{ date_to_x(today) }}"
203188
y1="0"
204-
y2="{{ (diagram_height - LINE_HEIGHT) * SCALE }}"
189+
y2="{{ diagram_height - line_height }}"
205190
font-size="{{ SCALE }}"
206191
/>
207192
</svg>

0 commit comments

Comments
 (0)