Skip to content

Commit ab8a033

Browse files
Add Core Web Vitals distribution histogram to tech report (#1241)
* Add Core Web Vitals distribution histogram to tech report drilldown Adds a collapsible histogram chart to the CWV section showing how origins are distributed across performance buckets for LCP, CLS, INP, FCP, and TTFB. Features: - Column chart with bars color-coded green/orange/red by CWV thresholds - Dashed plotlines marking good/needs-improvement boundaries - Tail buckets aggregated into an overflow "X+" bar so all origins are shown - Metric selector in the collapsed summary bar for quick switching - Loading spinner while the API call is in progress - Error message when data is unavailable - Light and dark mode support with theme-aware colors - Anchor link (#section-cwv_distribution) with auto-expand on direct navigation - URL hash updates when the section is expanded Fetches data from /v1/cwv-distribution (HTTPArchive/tech-report-apis#105) with technology, date, rank, and geo parameters. Also scopes the global .highcharts-point CSS rule to line/spline series only, so column chart bar colors are not overridden. Closes #1147 * Address PR review feedback - Rename title/description per suggestion ("Core Web Vitals histograms") - Restructure button bar so all 3 buttons appear first in DOM order, followed by content wrappers (fixes tab order) - Remove per-component metric selectors; the pass-rate timeseries selector now drives the geo breakdown and histogram via a shared cwv-metric-change event - Deep-linking works via ?good-cwv-over-time=CLS - Histogram resolves "overall" to LCP (has no combined view) - Titles update dynamically ("LCP histogram", "INP geographic breakdown") - Rename "Show distribution" button to "Show histogram" * Security errors * More fixes * Move config to JSON * Keep CodeQL happy * Hide hash --------- Co-authored-by: Barry Pollard <barrypollard@google.com>
1 parent a15d0cc commit ab8a033

File tree

12 files changed

+635
-54
lines changed

12 files changed

+635
-54
lines changed

config/last_updated.json

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@
5151
},
5252
"/static/css/techreport/techreport.css": {
5353
"date_published": "2023-10-09T00:00:00.000Z",
54-
"date_modified": "2026-03-24T00:00:00.000Z",
55-
"hash": "fed0915210b6a05bb8430623fe296586"
54+
"date_modified": "2026-04-14T00:00:00.000Z",
55+
"hash": "5a211ca184de3cd5731dfedaa1af929d"
5656
},
5757
"/static/js/accessibility.js": {
5858
"date_published": "2023-10-09T00:00:00.000Z",
@@ -166,18 +166,23 @@
166166
},
167167
"/static/js/techreport.js": {
168168
"date_published": "2023-10-09T00:00:00.000Z",
169-
"date_modified": "2026-03-10T00:00:00.000Z",
169+
"date_modified": "2026-04-14T00:00:00.000Z",
170170
"hash": "dfcef45ae09e7c2fcd3ab825e9503729"
171171
},
172+
"/static/js/techreport/cwvDistribution.js": {
173+
"date_published": "2026-04-07T00:00:00.000Z",
174+
"date_modified": "2026-04-14T00:00:00.000Z",
175+
"hash": "a9e884b2786b23670ac13e2c8a121183"
176+
},
172177
"/static/js/techreport/geoBreakdown.js": {
173178
"date_published": "2026-03-24T00:00:00.000Z",
174-
"date_modified": "2026-03-24T00:00:00.000Z",
175-
"hash": "030573b2da410620601352f9f6df8695"
179+
"date_modified": "2026-04-14T00:00:00.000Z",
180+
"hash": "2eab1a9b9c47001e8f5f757d041f4897"
176181
},
177182
"/static/js/techreport/section.js": {
178183
"date_published": "2023-10-09T00:00:00.000Z",
179-
"date_modified": "2026-03-24T00:00:00.000Z",
180-
"hash": "376404acd77a2e5adeab188a9b5ccb94"
184+
"date_modified": "2026-04-07T00:00:00.000Z",
185+
"hash": "c813fe60fb1bcd338221f72b64739701"
181186
},
182187
"/static/js/techreport/timeseries.js": {
183188
"date_published": "2023-10-09T00:00:00.000Z",
@@ -191,8 +196,8 @@
191196
},
192197
"/static/js/web-vitals.js": {
193198
"date_published": "2022-01-03T00:00:00.000Z",
194-
"date_modified": "2025-08-18T00:00:00.000Z",
195-
"hash": "e7b8ecda99703fdc7c6a33b6a3d07cc6"
199+
"date_modified": "2026-04-07T00:00:00.000Z",
200+
"hash": "1b30cb4e8907aa62bc9045690570a4eb"
196201
},
197202
"about.html": {
198203
"date_published": "2018-05-08T00:00:00.000Z",

config/techreport.json

Lines changed: 77 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,13 @@
1515
"INP",
1616
"TTFB"
1717
],
18+
"cwv_thresholds": {
19+
"LCP": [{ "value": 2500, "label": "Good" }, { "value": 4000, "label": "Needs improvement" }],
20+
"FCP": [{ "value": 1800, "label": "Good" }, { "value": 3000, "label": "Needs improvement" }],
21+
"TTFB": [{ "value": 800, "label": "Good" }, { "value": 1800, "label": "Needs improvement" }],
22+
"INP": [{ "value": 200, "label": "Good" }, { "value": 500, "label": "Needs improvement" }],
23+
"CLS": [{ "value": 0.1, "label": "Good" }, { "value": 0.25, "label": "Needs improvement" }]
24+
},
1825
"lighthouse_subcategories": [
1926
"accessibility",
2027
"best_practices",
@@ -726,14 +733,76 @@
726733
"id": "geo_breakdown",
727734
"title": "Core Web Vitals geographic breakdown",
728735
"description": "Top geographies by number of origins, showing the percentage with good Core Web Vitals and individual metrics.",
729-
"metric_options": [
730-
{ "label": "Good Core Web Vitals", "value": "overall" },
731-
{ "label": "Good LCP", "value": "LCP" },
732-
{ "label": "Good INP", "value": "INP" },
733-
{ "label": "Good CLS", "value": "CLS" },
734-
{ "label": "Good FCP", "value": "FCP" },
735-
{ "label": "Good TTFB", "value": "TTFB" }
736-
]
736+
"metric_labels": {
737+
"overall": "Good Core Web Vitals",
738+
"LCP": "Good LCP",
739+
"INP": "Good INP",
740+
"CLS": "Good CLS",
741+
"FCP": "Good FCP",
742+
"TTFB": "Good TTFB"
743+
}
744+
},
745+
"cwv_distribution": {
746+
"id": "cwv_distribution",
747+
"title": "Core Web Vitals histograms",
748+
"description": "How origins are distributed for individual Core Web Vitals metrics. Green, orange, and red zones indicate good, needs improvement, and poor thresholds respectively.",
749+
"metric_config": {
750+
"LCP": {
751+
"label": "LCP",
752+
"bucketField": "loading_bucket",
753+
"originsField": "lcp_origins",
754+
"unit": "ms",
755+
"axis_label": "LCP (ms)",
756+
"step": 100
757+
},
758+
"FCP": {
759+
"label": "FCP",
760+
"bucketField": "loading_bucket",
761+
"originsField": "fcp_origins",
762+
"unit": "ms",
763+
"axis_label": "FCP (ms)",
764+
"step": 100
765+
},
766+
"TTFB": {
767+
"label": "TTFB",
768+
"bucketField": "loading_bucket",
769+
"originsField": "ttfb_origins",
770+
"unit": "ms",
771+
"axis_label": "TTFB (ms)",
772+
"step": 100 },
773+
"INP": {
774+
"label": "INP",
775+
"bucketField": "inp_bucket",
776+
"originsField": "inp_origins",
777+
"unit": "ms",
778+
"axis_label": "INP (ms)",
779+
"step": 25
780+
},
781+
"CLS": {
782+
"label": "CLS",
783+
"bucketField": "cls_bucket",
784+
"originsField": "cls_origins",
785+
"unit": "",
786+
"axis_label": "CLS",
787+
"step": 0.05
788+
}
789+
},
790+
"zone_colors": {
791+
"light": {
792+
"good": "#0CCE6B",
793+
"needsImprovement": "#FFA400",
794+
"poor": "#FF4E42",
795+
"text": "#444",
796+
"gridLine": "#e6e6e6"
797+
},
798+
"dark": {
799+
"good": "#0CCE6B",
800+
"needsImprovement": "#FBBC04",
801+
"poor": "#FF6659",
802+
"text": "#ccc",
803+
"gridLine": "#444"
804+
}
805+
}
737806
}
738807
}
739808
},

0 commit comments

Comments
 (0)