chart = () => {
const svg = d3.create("svg")
.attr("width", chartwidth + margin.left + margin.right)
.attr("height", chartheight + margin.top + margin.bottom);
const filter = svg.append("filter")
.attr("id", "blur");
filter.append("feGaussianBlur")
.attr("in", "SourceAlpha")
.attr("stdDeviation", "3")
.attr("result", "blurred");
const feFlood = filter.append("feFlood")
.attr("flood-color", backgroundColor)
.attr("result", "color");
filter.append("feComposite")
.attr("in", "color")
.attr("in2", "blurred")
.attr("operator", "in")
.attr("result", "coloredBlur");
filter.append("feComponentTransfer")
.attr("in", "coloredBlur")
.attr("result", "brightnessAdjust")
.append("feFuncA")
.attr("type", "linear")
.attr("slope", "2");
filter.append("feMerge").selectAll("feMergeNode")
.data(["brightnessAdjust", "SourceGraphic"])
.join("feMergeNode")
.attr("in", d => d);
const g = svg.append("g")
.attr("transform", `translate(${[margin.left, margin.top]})`);
g.append("g")
.call(yaxisGenerator);
g.append("g")
.call(xaxisGenerator);
g.selectAll("circle")
.data(data)
.join("circle")
.attr("cx", d => x(d.year))
.attr("cy", d => y(d.mean))
.attr("fill", "none")
.attr("r", r)
.attr("stroke", "black");
g.append("path")
.datum(regression)
.attr("d", lineGenerator)
.attr("filter", "url(#blur)")
.attr("stroke", backgroundColor)
.attr("stroke-width", 1.5)
g.append("path")
.datum(regression)
.attr("d", lineGenerator)
.attr("fill", "none")
.attr("stroke", "black");
g.append("text")
.datum(regression)
.attr("font-family", franklinLight)
.attr("font-weight", "bold")
.attr("transform", d => {
const line = d.map(([dx, dy]) => [x(dx), y(dy)])
const angle = geometric.lineAngle(line);
return `translate(${geometric.pointTranslate(geometric.lineMidpoint(line), angle + 90, -5)}) rotate(${angle})`;
})
.style("paint-order", "stroke fill")
.style("stroke", "white")
.style("stroke-linejoin", "round")
.style("stroke-opacity", 0.8)
.style("stroke-width", "2px")
.text("TREND");
return svg.node();
}