legend = () => {
const wrapper = d3.create("div");
wrapper.append("div")
.style("font-family", franklinLight)
.style("line-height", "22px")
.style("margin-bottom", "4px")
.style("text-align", "center")
.html("Winter temperature change<br />per decade, 1980-2024");
const margin = { top: 0, bottom: 18 };
const width = 250;
const height = 16;
const scale = d3.scaleBand()
.domain(legendValues)
.range([0, width])
const svg = wrapper.append("svg")
.attr("width", width)
.attr("height", height + margin.top + margin.bottom)
.attr("font-family", franklinLight)
.style("margin", "0 auto")
.style("display", "table")
.style("overflow", "visible");
const g = svg.append("g")
.attr("transform", `translate(0, ${margin.top})`)
const tickValues = [...d3.range(-1, 0.5, 0.5), coldValues[0], ...d3.range(0, 2, 0.5)]
const tick = g.selectAll(".tick")
.data(legendValues)
.join("g")
.attr("class", "tick")
.attr("transform", d => `translate(${scale(d)})`);
const epsilon = 1e-6;
tick.append("rect")
.attr("fill", d => d > 0 ? colorScale(d - epsilon) : colorScale(d + epsilon))
.attr("height", height)
.attr("x", -0.5)
.attr("width", (_, i, e) => scale.bandwidth() + (i < e.length - 1 ? 1 : 0));
tick.append("line")
.filter(d => tickValues.includes(d))
.attr("stroke", "black")
.attr("transform", d => `translate(${d >= coldValues[0] ? scale.bandwidth() : 0})`)
.attr("y1", height)
.attr("y2", height + 4);
tick.append("text")
.filter(d => tickValues.includes(d))
.attr("font-size", 14)
.attr("text-anchor", "middle")
.attr("transform", d => `translate(${d >= coldValues[0] ? scale.bandwidth() : 0})`)
.attr("y", height + 17)
.text((d, i, e) => d === coldValues[0] ? "0" : `${d < 0 ? "-" : d > 0 ? "+" : ""}${Math.abs(d)}${i === e.length - 1 ? "°F" : ""}`);
return wrapper.node();
}