Skip to content

Commit fb64044

Browse files
committed
Revert "fix: remove cartogram"
This reverts commit f891cb5.
1 parent f891cb5 commit fb64044

3 files changed

Lines changed: 167 additions & 127 deletions

File tree

website/config/_default/params.toml

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@ fingerprintAlgorithm = "sha256"
4747
showHeadingAnchors = true
4848
showPagination = true
4949
invertPagination = false
50-
showReadingTime = false
51-
showTableOfContents = false
50+
showReadingTime = true
51+
showTableOfContents = true
5252
showTaxonomies = false
5353
showWordCount = false
5454
showComments = false
@@ -67,3 +67,16 @@ fingerprintAlgorithm = "sha256"
6767

6868
[taxonomy]
6969
showTermCount = true
70+
71+
[fathomAnalytics]
72+
# site = "ABC12345"
73+
74+
#[umamiAnalytics]
75+
# site = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
76+
# region = "eu" # Can be either "eu" or "us"
77+
78+
[verification]
79+
# google = ""
80+
# bing = ""
81+
# pinterest = ""
82+
# yandex = ""

website/content/_index.md

Lines changed: 151 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -19,128 +19,154 @@ A powerful, lightweight visualization for COM-480 built with Hugo, Tailwind CSS.
1919
- [Languages](visualizations/languages/): see the distribution of books by language as a waffle chart.
2020
- [Publishers](visualizations/publishers/): compare gender representation across major publishers.
2121
- [Library](visualizations/library/): browse and filter books on an interactive shelf.
22-
## Scale countries by amount of books published by author's from these countries
23-
# Cartogram
24-
!-- prettier-ignore-start -->
25-
script src="https://unpkg.com/topojson@3/dist/topojson.min.js"></script>
26-
script src="{{< asset-url "js/cartogram.js" >}}"></script>
27-
{< d3 >}}
28-
onst width = container.clientWidth;
29-
onst height = 500;
30-
onst svg = d3.select(container).append("svg")
31-
.attr("width", width)
32-
.attr("height", height);
33-
onst genderLabels = {
34-
"m": "Male",
35-
"w": "Female",
36-
"w;m": "Female & Male",
37-
"m;m": "Male & Male",
38-
"m;m;m": "Male & Male & Male",
39-
"w;w": "Female & Female"
40-
;
41-
onst genders = Object.keys(genderLabels);
42-
onst isDark = document.documentElement.classList.contains("dark");
43-
onst labelColor = isDark ? congoColors.neutral100 : "#000000";
44-
onst selector = d3.select(container).insert("div", "svg")
45-
.style("margin-bottom", "10px");
46-
elector.append("label")
47-
.text("Select gender: ")
48-
.style("color", labelColor);
49-
onst select = selector.append("select")
50-
.style("margin-bottom", "8px")
51-
.style("padding", "6px 12px")
52-
.style("background", congoColors.primary400)
53-
.style("color", congoColors.neutral100)
54-
.style("border", "none")
55-
.style("border-radius", "4px")
56-
.style("cursor", "pointer");
57-
romise.all([
58-
d3.json("https://cdn.jsdelivr.net/npm/world-atlas@2/countries-110m.json"),
59-
d3.csv("{{< asset-url "data/nationalities.csv" >}}")
60-
).then(([topology, data]) => {
61-
const dataById = new Map(
62-
data
63-
.filter(d => d["ID"] && d["ID"] !== "nan")
64-
.map(d => [+d["ID"], { counts: +d["counts"], name: d["nationality"] }])
65-
);
66-
const nameById = new Map(
67-
topology.objects.countries.geometries.map(d => [+d.id, d.properties?.name ?? "Unknown"])
68-
);
69-
// Split geometries
70-
const problematicIDs = [10, 643, 242]; // Antarctica, Russia
71-
const cartoGeometries = topology.objects.countries.geometries
72-
.filter(d => !problematicIDs.includes(+d.id));
73-
const staticGeometries = topology.objects.countries.geometries
74-
.filter(d => problematicIDs.includes(+d.id)); // Russia yes, Antarctica no
75-
const values = cartoGeometries.map(d => dataById.get(+d.id)?.counts ?? 0);
76-
const lo = d3.min(values), hi = d3.max(values);
77-
const scale = d3.scaleLinear().domain([lo, hi]).range([1, 20]);
78-
const colorScale = d3.scaleSequentialLog(d3.interpolate(
79-
congoColors.neutral100,
80-
congoColors.primary500
81-
)).domain([1, hi]);
82-
const color = d => {
83-
const counts = dataById.get(+d.id)?.counts ?? 0;
84-
return counts === 0 ? congoColors.neutral100 : colorScale(counts);
85-
};
86-
// Tooltip handlers
87-
const onMouseover = (event, d) => {
88-
const id = +d.id;
89-
const entry = dataById.get(id);
90-
const name = entry?.name ?? nameById.get(id) ?? "Unknown";
91-
const counts = entry?.counts ?? 0;
92-
tooltip.style("opacity", 1)
93-
.html(`<strong>${name}</strong><br/>${counts} book${counts !== 1 ? "s" : ""}`);
94-
};
95-
const onMousemove = (event) => {
96-
const [x, y] = d3.pointer(event, container);
97-
tooltip
98-
.style("left", `${x + 12}px`)
99-
.style("top", `${y - 28}px`);
100-
};
101-
const onMouseout = () => tooltip.style("opacity", 0);
102-
carto
103-
.properties(d => ({ id: d.ID }))
104-
.value(d => scale(dataById.get(+d.id)?.counts ?? 0));
105-
const features = carto(topology, cartoGeometries).features;
106-
const cartoFeatures = carto(topology, cartoGeometries).features;
107-
const normalFeatures = cartoGeometries.map(d => topojson.feature(topology, d));
108-
// Draw exluded countries because of anti-meridian as static layer first
109-
svg.selectAll(".static-country")
110-
.data(staticGeometries.map(d => topojson.feature(topology, d)))
111-
.enter().append("path")
112-
.attr("class", "static-country")
113-
.attr("d", staticPath)
114-
.attr("fill", color)
115-
.attr("stroke", congoColors.neutral100)
116-
.attr("stroke-width", 0.5)
117-
.on("mouseover", onMouseover)
118-
.on("mousemove", onMousemove)
119-
.on("mouseout", onMouseout);
120-
// Draw cartogram countries
121-
const paths = svg.selectAll(".carto-country")
122-
.data(cartoFeatures)
123-
.enter().append("path")
124-
.attr("class", "carto-country")
125-
.attr("d", carto.path)
126-
.attr("fill", color)
127-
.attr("stroke", congoColors.neutral100)
128-
.attr("stroke-width", 0.5)
129-
.on("mouseover", onMouseover)
130-
.on("mousemove", onMousemove)
131-
.on("mouseout", onMouseout);
132-
// Toggle between distorted and normal
133-
button.on("click", () => {
134-
distorted = !distorted;
135-
button.text(distorted ? "Show Normal Map" : "Show Cartogram");
136-
paths.transition().duration(750)
137-
.attr("d", (d, i) => distorted
138-
? carto.path(d)
139-
: staticPath(normalFeatures[i])
140-
);
141-
});
142-
).catch(err => {
143-
console.error("Error loading data:", err);
144-
);
145-
{< /d3 >}}
146-
!-- prettier-ignore-end -->
22+
23+
### Scale countries by amount of books published by author's from these countries
24+
25+
26+
## Cartogram
27+
28+
<!-- prettier-ignore-start -->
29+
<script src="https://unpkg.com/topojson@3/dist/topojson.min.js"></script>
30+
<script src="{{< asset-url "js/cartogram.js" >}}"></script>
31+
32+
{{< d3 >}}
33+
const width = container.clientWidth;
34+
const height = 500;
35+
const svg = d3.select(container).append("svg")
36+
.attr("width", width)
37+
.attr("height", height);
38+
39+
const genderLabels = {
40+
"m": "Male",
41+
"w": "Female",
42+
"w;m": "Female & Male",
43+
"m;m": "Male & Male",
44+
"m;m;m": "Male & Male & Male",
45+
"w;w": "Female & Female"
46+
};
47+
const genders = Object.keys(genderLabels);
48+
const isDark = document.documentElement.classList.contains("dark");
49+
const labelColor = isDark ? congoColors.neutral100 : "#000000";
50+
51+
const selector = d3.select(container).insert("div", "svg")
52+
.style("margin-bottom", "10px");
53+
selector.append("label")
54+
.text("Select gender: ")
55+
.style("color", labelColor);
56+
const select = selector.append("select")
57+
.style("margin-bottom", "8px")
58+
.style("padding", "6px 12px")
59+
.style("background", congoColors.primary400)
60+
.style("color", congoColors.neutral100)
61+
.style("border", "none")
62+
.style("border-radius", "4px")
63+
.style("cursor", "pointer");
64+
65+
Promise.all([
66+
d3.json("https://cdn.jsdelivr.net/npm/world-atlas@2/countries-110m.json"),
67+
d3.csv("{{< asset-url "data/nationalities.csv" >}}")
68+
]).then(([topology, data]) => {
69+
const dataById = new Map(
70+
data
71+
.filter(d => d["ID"] && d["ID"] !== "nan")
72+
.map(d => [+d["ID"], { counts: +d["counts"], name: d["nationality"] }])
73+
);
74+
const nameById = new Map(
75+
topology.objects.countries.geometries.map(d => [+d.id, d.properties?.name ?? "Unknown"])
76+
);
77+
78+
79+
// Split geometries
80+
const problematicIDs = [10, 643, 242]; // Antarctica, Russia
81+
const cartoGeometries = topology.objects.countries.geometries
82+
.filter(d => !problematicIDs.includes(+d.id));
83+
84+
const staticGeometries = topology.objects.countries.geometries
85+
.filter(d => problematicIDs.includes(+d.id)); // Russia yes, Antarctica no
86+
87+
88+
const values = cartoGeometries.map(d => dataById.get(+d.id)?.counts ?? 0);
89+
90+
const lo = d3.min(values), hi = d3.max(values);
91+
92+
const scale = d3.scaleLinear().domain([lo, hi]).range([1, 20]);
93+
const colorScale = d3.scaleSequentialLog(d3.interpolate(
94+
congoColors.neutral100,
95+
congoColors.primary500
96+
)).domain([1, hi]);
97+
98+
const color = d => {
99+
const counts = dataById.get(+d.id)?.counts ?? 0;
100+
return counts === 0 ? congoColors.neutral100 : colorScale(counts);
101+
};
102+
103+
// Tooltip handlers
104+
const onMouseover = (event, d) => {
105+
const id = +d.id;
106+
const entry = dataById.get(id);
107+
const name = entry?.name ?? nameById.get(id) ?? "Unknown";
108+
const counts = entry?.counts ?? 0;
109+
tooltip.style("opacity", 1)
110+
.html(`<strong>${name}</strong><br/>${counts} book${counts !== 1 ? "s" : ""}`);
111+
};
112+
113+
const onMousemove = (event) => {
114+
const [x, y] = d3.pointer(event, container);
115+
tooltip
116+
.style("left", `${x + 12}px`)
117+
.style("top", `${y - 28}px`);
118+
};
119+
120+
const onMouseout = () => tooltip.style("opacity", 0);
121+
122+
carto
123+
.properties(d => ({ id: d.ID }))
124+
.value(d => scale(dataById.get(+d.id)?.counts ?? 0));
125+
126+
const features = carto(topology, cartoGeometries).features;
127+
const cartoFeatures = carto(topology, cartoGeometries).features;
128+
const normalFeatures = cartoGeometries.map(d => topojson.feature(topology, d));
129+
130+
// Draw exluded countries because of anti-meridian as static layer first
131+
svg.selectAll(".static-country")
132+
.data(staticGeometries.map(d => topojson.feature(topology, d)))
133+
.enter().append("path")
134+
.attr("class", "static-country")
135+
.attr("d", staticPath)
136+
.attr("fill", color)
137+
.attr("stroke", congoColors.neutral100)
138+
.attr("stroke-width", 0.5)
139+
.on("mouseover", onMouseover)
140+
.on("mousemove", onMousemove)
141+
.on("mouseout", onMouseout);
142+
143+
// Draw cartogram countries
144+
const paths = svg.selectAll(".carto-country")
145+
.data(cartoFeatures)
146+
.enter().append("path")
147+
.attr("class", "carto-country")
148+
.attr("d", carto.path)
149+
.attr("fill", color)
150+
.attr("stroke", congoColors.neutral100)
151+
.attr("stroke-width", 0.5)
152+
.on("mouseover", onMouseover)
153+
.on("mousemove", onMousemove)
154+
.on("mouseout", onMouseout);
155+
156+
// Toggle between distorted and normal
157+
button.on("click", () => {
158+
distorted = !distorted;
159+
button.text(distorted ? "Show Normal Map" : "Show Cartogram");
160+
161+
paths.transition().duration(750)
162+
.attr("d", (d, i) => distorted
163+
? carto.path(d)
164+
: staticPath(normalFeatures[i])
165+
);
166+
});
167+
168+
}).catch(err => {
169+
console.error("Error loading data:", err);
170+
});
171+
{{< /d3 >}}
172+
<!-- prettier-ignore-end -->

website/content/festivities.svg

Lines changed: 1 addition & 0 deletions
Loading

0 commit comments

Comments
 (0)