{
const svg = d3
.create("svg")
.attr("width", (width + margin.left + margin.right) * 6 + margin.right)
.attr("height", (height + margin.top + margin.bottom) * 4 + margin.bottom)
.attr(
"style",
"max-width: 100%; height: auto; font-size: 10px; font-family: 'Inter', sans-serif;"
);
d3.select("#startAnimationButton").on("click", function () {
startAnimation();
});
const defs = svg.append("defs");
defs
.append("linearGradient")
.attr("id", "gradientBlue")
.attr("gradientTransform", "rotate(0)")
.selectAll("stop")
.data([
{ offset: "25%", color: "white", opacity: "0" },
{ offset: "100%", color: "#3f6bee", opacity: "0.7" }
])
.enter()
.append("stop")
.attr("offset", (d) => d.offset)
.attr("stop-color", (d) => d.color)
.attr("stop-opacity", (d) => d.opacity);
defs
.append("linearGradient")
.attr("id", "gradientRed")
.attr("gradientTransform", "rotate(0)")
.selectAll("stop")
.data([
{ offset: "25%", color: "white", opacity: "0" },
{ offset: "100%", color: "#e61f00", opacity: "0.7" }
])
.enter()
.append("stop")
.attr("offset", (d) => d.offset)
.attr("stop-color", (d) => d.color)
.attr("stop-opacity", (d) => d.opacity);
const xScale = d3
.scaleTime()
.domain(d3.extent(data, (d) => d.year))
.range([0, width]);
function startAnimation() {
const nestedData = d3.group(data, (d) => d.labels);
const facets = svg
.selectAll("g")
.data(nestedData)
.enter()
.append("g")
.attr("opacity", 0)
.attr(
"transform",
(d, i) =>
`translate(${
(i % 6) * (width + margin.left + margin.right) + margin.left
},${
Math.floor(i / 6) * (height + margin.top + margin.bottom) +
margin.top
})`
);
let surfacetempLine;
facets.each(function (d, i) {
const [label, values] = d;
const yScale = d3
.scaleLinear()
.domain(d3.extent(values, (v) => v.values))
.range([height, 0])
.nice();
const line1950 = d3
.select(this)
.append("line")
.attr("x1", xScale(new Date("1950")))
.attr("x2", xScale(new Date("1950")))
.attr("y1", 0)
.attr("y2", height)
.attr("stroke", "gray")
.attr("stroke-width", 1)
.attr("stroke-dasharray", "5,5")
.attr("opacity", 0);
if (label === "Surface Temperature") {
surfacetempLine = d3
.select(this)
.append("line")
.attr("x1", 0)
.attr("x2", width)
.attr("y1", yScale(0))
.attr("y2", yScale(0))
.attr("stroke", "black")
.attr("stroke-width", 1)
.attr("opacity", 0);
}
d3.select(this)
.transition()
.duration(animationInterval * 0.2)
.delay(animationInterval * i)
.attr("opacity", 1)
.on("end", function () {
const yAxis = d3
.select(this)
.append("g")
.attr("opacity", 0)
.call(d3.axisLeft(yScale).tickSize(0).tickPadding(6).ticks(4));
const xAxis = d3
.select(this)
.append("g")
.attr("opacity", 0)
.attr("transform", `translate(0,${height})`)
.call(d3.axisBottom(xScale).tickValues(specificTicks));
if (yScale.domain()[0] !== 0) {
xAxis.select(".domain").remove();
}
yAxis.transition().duration(500).attr("opacity", 1);
xAxis.transition().duration(500).attr("opacity", 1);
surfacetempLine
.transition()
.duration(animationInterval * 1.2)
.attr("opacity", 1);
line1950
.transition()
.duration(animationInterval * 1.2)
.attr("opacity", 1);
d3.select(this)
.selectAll(".grid-line")
.data(yScale.ticks(4))
.enter()
.append("line")
.attr("class", "grid-line")
.attr("x1", 0)
.attr("x2", width)
.attr("y1", (d) => yScale(d))
.attr("y2", (d) => yScale(d))
.attr("stroke", "#ccc")
.attr("stroke-width", 1)
.attr("opacity", 0)
.transition()
.duration(500)
.attr("opacity", 0.5);
const areaGenerator = d3
.area()
.x((d) => xScale(d.year))
.y0(height)
.y1((d) => yScale(d.values))
.curve(d3.curveNatural);
const area = d3
.select(this)
.append("path")
.datum(values)
.attr("fill", function (d) {
return d[0].trend_type === "Socio-economic Trends"
? "url(#gradientBlue)"
: "url(#gradientRed)";
})
.attr("opacity", 0)
.attr("d", areaGenerator);
area
.transition()
.duration(animationInterval * 1.2)
.attr("opacity", 1);
const whitePath = d3
.select(this)
.append("path")
.datum(values)
.attr("fill", "none")
.attr("stroke", "white")
.attr("stroke-width", 3)
.attr(
"d",
d3
.line()
.x((d) => xScale(d.year))
.y((d) => yScale(d.values))
.curve(d3.curveNatural)
)
.attr("stroke-dasharray", function () {
return `${this.getTotalLength()} ${this.getTotalLength()}`;
})
.attr("stroke-dashoffset", function () {
return this.getTotalLength();
});
whitePath
.transition()
.duration(animationInterval * 0.8)
.attr("stroke-dashoffset", 0);
const path = d3
.select(this)
.append("path")
.datum(values)
.attr("fill", "none")
.attr(
"stroke",
values[0].trend_type === "Socio-economic Trends"
? "#3f6bee"
: "#e61f00"
)
.attr("stroke-width", 1.5)
.attr(
"d",
d3
.line()
.x((d) => xScale(d.year))
.y((d) => yScale(d.values))
.curve(d3.curveNatural)
)
.attr("stroke-dasharray", function () {
return `${this.getTotalLength()} ${this.getTotalLength()}`;
})
.attr("stroke-dashoffset", function () {
return this.getTotalLength();
});
path
.transition()
.duration(animationInterval * 0.8)
.attr("stroke-dashoffset", 0);
const labelFade = d3
.select(this)
.append("text")
.attr("x", 2.5)
.attr("y", 4)
.attr("font-size", "13.5px")
.attr("font-weight", "bold")
.style(
"text-shadow",
"-1px -1px 0 #fff, 1px -1px 0 #fff, -1px 1px 0 #fff, 1px 1px 0 #fff"
)
.text(label)
.call(wrapText, 10);
labelFade.transition().duration(500).attr("opacity", 1);
const yLabel = d3
.select(this)
.append("text")
.attr("x", -20)
.attr("y", -12)
.text(values[0].yAxisLabels);
yLabel.transition().duration(500).attr("opacity", 1);
});
});
}
return svg.node();
}