Skip to content

Commit d24d2ac

Browse files
committed
show bar chart instead of map on small screens
1 parent a44bace commit d24d2ac

2 files changed

Lines changed: 81 additions & 12 deletions

File tree

src/components/country-map.scss

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,17 @@
1212

1313
country-map {
1414
display: block;
15-
// Reserve space before svgmap loads to avoid layout shift
16-
aspect-ratio: auto 2 / 1;
17-
// 550px: comfortable max on large screens (leaves room for navbar, heading, footer on 900px viewports)
18-
// 65dvh: viewport-relative cap so the map never causes vertical scrolling
19-
max-height: min(550px, 65dvh);
2015

21-
// Propagate max-height into svgmap's padding-based layout
22-
.svgMap-map-wrapper {
23-
max-height: inherit;
16+
@media (min-width: 769px) {
17+
// Reserve space before svgmap loads to avoid layout shift
18+
aspect-ratio: auto 2 / 1;
19+
// 550px: comfortable max on large screens (leaves room for navbar, heading, footer on 900px viewports)
20+
// 65dvh: viewport-relative cap so the map never causes vertical scrolling
21+
max-height: min(550px, 65dvh);
22+
23+
// Propagate max-height into svgmap's padding-based layout
24+
.svgMap-map-wrapper {
25+
max-height: inherit;
26+
}
2427
}
2528
}

src/components/country-map.ts

Lines changed: 70 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,77 @@ class CountryMap extends HTMLElement {
2121
return;
2222
}
2323

24-
const container = document.createElement("div");
25-
container.id = `countries-map-${Math.random().toString(36).slice(2)}`;
26-
this.appendChild(container);
24+
const isSmallScreen = window.matchMedia("(max-width: 768px)").matches;
2725

28-
this.renderMap(container.id, values);
26+
if (isSmallScreen) {
27+
this.renderBarChart(values);
28+
} else {
29+
const container = document.createElement("div");
30+
container.id = `countries-map-${Math.random().toString(36).slice(2)}`;
31+
this.appendChild(container);
32+
this.renderMap(container.id, values);
33+
}
34+
}
35+
36+
private async renderBarChart(
37+
values: Record<string, { popularity: number }>,
38+
) {
39+
const sorted = Object.entries(values).sort(
40+
([, a], [, b]) => b.popularity - a.popularity,
41+
);
42+
43+
const regionNames = new Intl.DisplayNames(["en"], { type: "region" });
44+
const labels = sorted.map(([code]) => regionNames.of(code) ?? code);
45+
const data = sorted.map(([, v]) => v.popularity);
46+
47+
const { Chart, BarElement, BarController, CategoryScale, LinearScale } =
48+
await import("chart.js");
49+
50+
Chart.register(BarElement, BarController, CategoryScale, LinearScale);
51+
52+
const canvas = document.createElement("canvas");
53+
canvas.style.height = `${sorted.length * 25}px`;
54+
this.appendChild(canvas);
55+
56+
const style = getComputedStyle(document.documentElement);
57+
const textColor = style.getPropertyValue("--bs-body-color");
58+
const gridColor = style.getPropertyValue("--bs-border-color");
59+
const primaryColor = style.getPropertyValue("--bs-primary");
60+
61+
new Chart(canvas, {
62+
type: "bar",
63+
data: {
64+
labels,
65+
datasets: [
66+
{
67+
data,
68+
backgroundColor: primaryColor,
69+
},
70+
],
71+
},
72+
options: {
73+
indexAxis: "y",
74+
animation: false,
75+
maintainAspectRatio: false,
76+
events: [],
77+
plugins: {
78+
legend: { display: false },
79+
},
80+
scales: {
81+
x: {
82+
min: 0,
83+
border: { color: gridColor },
84+
grid: { color: gridColor },
85+
ticks: { color: textColor },
86+
},
87+
y: {
88+
border: { color: gridColor },
89+
grid: { display: false },
90+
ticks: { color: textColor },
91+
},
92+
},
93+
},
94+
});
2995
}
3096

3197
private async renderMap(

0 commit comments

Comments
 (0)