|
| 1 | +--- |
| 2 | +const data = [ |
| 3 | + { name: "Ada", ns: 188 }, |
| 4 | + { name: "Servo URL", ns: 664 }, |
| 5 | + { name: "cURL", ns: 1471 }, |
| 6 | +] |
| 7 | +const max = 2000 |
| 8 | +--- |
| 9 | + |
1 | 10 | <section aria-labelledby="benchmarks-heading"> |
2 | 11 | <header> |
3 | 12 | <h2 id="benchmarks-heading">Ada is fast</h2> |
|
10 | 19 | </a>{" "} we find that ada can be several times faster than popular competitors. |
11 | 20 | </p> |
12 | 21 | </header> |
13 | | - <div> |
14 | | - <div style="width: 800px;" class="container-chart"> |
15 | | - <canvas |
16 | | - id="acquisitions" |
17 | | - role="img" |
18 | | - aria-label="Bar chart comparing URL parsing speed: Ada 188 ns/URL, Servo URL 664 ns/URL, cURL 1471 ns/URL" |
19 | | - ></canvas> |
| 22 | + <figure> |
| 23 | + <figcaption class="sr-only">URL parsing speed comparison (lower is faster)</figcaption> |
| 24 | + <div class="bar-chart"> |
| 25 | + {data.map(({ name, ns }) => ( |
| 26 | + <div class="bar-row"> |
| 27 | + <span class="bar-label">{name}</span> |
| 28 | + <div class="bar-track"> |
| 29 | + <div class="bar" style={`--w: ${(ns / max * 100).toFixed(2)}%`}></div> |
| 30 | + </div> |
| 31 | + <span class="bar-value">{ns}<abbr title="nanoseconds per URL"> ns/URL</abbr></span> |
| 32 | + </div> |
| 33 | + ))} |
20 | 34 | </div> |
21 | | - <!-- Visually-hidden text alternative for screen readers --> |
22 | | - <table class="sr-only"> |
23 | | - <caption>URL parsing speed comparison (lower is faster)</caption> |
24 | | - <thead> |
25 | | - <tr> |
26 | | - <th scope="col">Parser</th> |
27 | | - <th scope="col">Speed (ns/URL)</th> |
28 | | - </tr> |
29 | | - </thead> |
30 | | - <tbody> |
31 | | - <tr><td>Ada</td><td>188</td></tr> |
32 | | - <tr><td>Servo URL</td><td>664</td></tr> |
33 | | - <tr><td>cURL</td><td>1471</td></tr> |
34 | | - </tbody> |
35 | | - </table> |
36 | | - </div> |
| 35 | + </figure> |
37 | 36 | </section> |
38 | 37 |
|
39 | 38 | <style> |
|
72 | 71 | a { |
73 | 72 | font-weight: 700; |
74 | 73 | } |
75 | | - |
76 | | - .container-chart { |
77 | | - max-width: 100%; |
78 | | - margin-inline: auto; |
| 74 | + |
| 75 | + figure { |
| 76 | + margin: 0; |
79 | 77 | } |
80 | 78 |
|
81 | | - /* Visually hidden but accessible to screen readers */ |
82 | 79 | .sr-only { |
83 | 80 | position: absolute; |
84 | 81 | width: 1px; |
|
91 | 88 | border-width: 0; |
92 | 89 | } |
93 | 90 |
|
| 91 | + .bar-chart { |
| 92 | + display: flex; |
| 93 | + flex-direction: column; |
| 94 | + gap: 0.75rem; |
| 95 | + max-width: 800px; |
| 96 | + margin-inline: auto; |
| 97 | + width: 100%; |
| 98 | + } |
| 99 | + |
| 100 | + .bar-row { |
| 101 | + display: grid; |
| 102 | + grid-template-columns: 6.5rem 1fr 6.5rem; |
| 103 | + align-items: center; |
| 104 | + gap: 0.75rem; |
| 105 | + } |
| 106 | + |
| 107 | + .bar-label { |
| 108 | + text-align: right; |
| 109 | + font-size: 0.875rem; |
| 110 | + font-weight: 700; |
| 111 | + color: var(--sl-color-gray-3); |
| 112 | + } |
| 113 | + |
| 114 | + .bar-track { |
| 115 | + height: 2.5rem; |
| 116 | + border-radius: 0.5rem; |
| 117 | + background: var(--sl-color-gray-6); |
| 118 | + overflow: hidden; |
| 119 | + } |
| 120 | + |
| 121 | + .bar { |
| 122 | + height: 100%; |
| 123 | + width: var(--w); |
| 124 | + background: #8884d8; |
| 125 | + border-radius: 0.5rem; |
| 126 | + transition: background 0.15s; |
| 127 | + } |
| 128 | + |
| 129 | + .bar:hover { |
| 130 | + background: #7874c8; |
| 131 | + } |
| 132 | + |
| 133 | + .bar-value { |
| 134 | + font-size: 0.75rem; |
| 135 | + font-variant-numeric: tabular-nums; |
| 136 | + color: var(--sl-color-gray-3); |
| 137 | + } |
| 138 | + |
| 139 | + abbr { |
| 140 | + text-decoration: none; |
| 141 | + } |
| 142 | + |
94 | 143 | :root[data-theme="dark"] { |
95 | | - & p { |
| 144 | + & p, |
| 145 | + & .bar-label, |
| 146 | + & .bar-value { |
96 | 147 | color: var(--sl-color-gray-2); |
97 | 148 | } |
98 | 149 |
|
|
103 | 154 |
|
104 | 155 | @media (max-width: 768px) { |
105 | 156 | h2 { |
106 | | - font-size: 1.875rem; |
107 | | - line-height: 2.25rem; |
| 157 | + font-size: 1.875rem; |
| 158 | + line-height: 2.25rem; |
| 159 | + } |
| 160 | + |
| 161 | + .bar-row { |
| 162 | + grid-template-columns: 5.5rem 1fr 5rem; |
108 | 163 | } |
109 | 164 | } |
110 | 165 |
|
111 | 166 | @media (min-width: 640px) { |
112 | | - |
113 | | - |
114 | 167 | p { |
115 | 168 | font-size: 1.125rem; |
116 | 169 | line-height: 1.75rem; |
|
122 | 175 | max-width: 1400px; |
123 | 176 | } |
124 | 177 | } |
125 | | -</style> |
126 | | - |
127 | | -<script> |
128 | | - import { |
129 | | - Chart, |
130 | | - BarController, |
131 | | - BarElement, |
132 | | - CategoryScale, |
133 | | - LinearScale, |
134 | | - Legend, |
135 | | - Tooltip, |
136 | | - } from "chart.js"; |
137 | | - |
138 | | - Chart.register(BarController, BarElement, CategoryScale, LinearScale, Legend, Tooltip); |
139 | | - |
140 | | - function getChartColors() { |
141 | | - const style = getComputedStyle(document.documentElement); |
142 | | - // Use Starlight's own grey tokens so colours adapt to both themes |
143 | | - const tickColor = |
144 | | - style.getPropertyValue("--sl-color-gray-3").trim() || "#6b7280"; |
145 | | - const gridColor = |
146 | | - style.getPropertyValue("--sl-color-gray-6").trim() || |
147 | | - "rgba(107,114,128,0.2)"; |
148 | | - return { tickColor, gridColor }; |
149 | | - } |
150 | | - |
151 | | - const data = [ |
152 | | - { competitors: "Ada", count: 188 }, |
153 | | - { competitors: "Servo URL", count: 664 }, |
154 | | - { competitors: "cURL", count: 1471 }, |
155 | | - ]; |
156 | | - |
157 | | - let chart: Chart | null = null; |
158 | | - |
159 | | - function buildChart() { |
160 | | - const canvas = document.getElementById( |
161 | | - "acquisitions" |
162 | | - ) as HTMLCanvasElement | null; |
163 | | - if (!canvas) return; |
164 | | - |
165 | | - if (chart) chart.destroy(); |
166 | | - |
167 | | - const { tickColor, gridColor } = getChartColors(); |
168 | | - |
169 | | - chart = new Chart(canvas, { |
170 | | - type: "bar", |
171 | | - options: { |
172 | | - indexAxis: "y", |
173 | | - scales: { |
174 | | - x: { |
175 | | - max: 2000, |
176 | | - ticks: { |
177 | | - maxTicksLimit: 5, |
178 | | - callback: function (value) { |
179 | | - return `${value}ns`; |
180 | | - }, |
181 | | - color: tickColor, |
182 | | - }, |
183 | | - grid: { |
184 | | - display: true, |
185 | | - color: gridColor, |
186 | | - }, |
187 | | - }, |
188 | | - y: { |
189 | | - ticks: { |
190 | | - color: tickColor, |
191 | | - }, |
192 | | - grid: { |
193 | | - display: false, |
194 | | - }, |
195 | | - }, |
196 | | - }, |
197 | | - plugins: { |
198 | | - legend: { |
199 | | - display: false, |
200 | | - }, |
201 | | - tooltip: { |
202 | | - displayColors: false, |
203 | | - callbacks: { |
204 | | - title: function () { |
205 | | - return ""; |
206 | | - }, |
207 | | - label: function (tooltipItem: { raw: any }) { |
208 | | - const value = tooltipItem.raw; |
209 | | - return `${value}ns`; |
210 | | - }, |
211 | | - }, |
212 | | - }, |
213 | | - }, |
214 | | - }, |
215 | | - data: { |
216 | | - labels: data.map((row) => row.competitors), |
217 | | - datasets: [ |
218 | | - { |
219 | | - data: data.map((row) => row.count), |
220 | | - backgroundColor: "#8884D8", |
221 | | - hoverBackgroundColor: "#7874C8", |
222 | | - borderRadius: 10, |
223 | | - maxBarThickness: 45, |
224 | | - }, |
225 | | - ], |
226 | | - }, |
227 | | - }); |
228 | | - } |
229 | | - |
230 | | - buildChart(); |
231 | | - |
232 | | - // Rebuild the chart whenever Starlight switches between light and dark themes |
233 | | - // so tick/grid colours stay legible in both modes. |
234 | | - new MutationObserver(() => buildChart()).observe(document.documentElement, { |
235 | | - attributes: true, |
236 | | - attributeFilter: ["data-theme"], |
237 | | - }); |
238 | | -</script> |
| 178 | +</style> |
0 commit comments