chart = {
const zero = 0.6;
const zeroAxis = 0.4;
const svg = d3
.create('svg')
.attr('class', 'chart')
.attr('viewBox', [0, 0, width, height]);
yield svg.node();
const line = d3.line().curve(cumulative ? d3.curveMonotoneY : d3.curveLinear);
const seriesGroups = svg
.selectAll('g')
.data(series)
.join('g');
const lines = seriesGroups
.append('path')
.attr('d', d => {
let points = d[1].map(d => [
x(d[1][axisX] || zero),
y(d[1][axisY] || zero)
]);
return line(points);
})
.style('fill', 'none')
.style('stroke-width', 1.5)
.style('stroke', d => color(groupBy === 'total' ? 1 : d[1][0][1][groupBy]));
const circles = seriesGroups
.style('fill', d => color(groupBy === 'total' ? 1 : d[1][0][1][groupBy]))
.selectAll('circle')
.data(d => (showPoints ? d[1] : []))
.join('circle');
circles
.attr('r', 2.5)
.attr('cx', d => x(d[1][axisX]))
.attr('cy', d => y(d[1][axisY]));
const axis = svg.append('g');
const axisB = d3.axisBottom(x),
axisL = d3.axisLeft(y);
const formatN = d3.format(","),
logTickFormat = d => ((Math.log10(d) - Math.floor(Math.log10(d))) === 0 ? formatN(d) : "");
if (logScale) {
axisL.tickFormat(logTickFormat);
if (axisX !== "date") axisB.tickFormat(logTickFormat);
}
axis
.append('g')
.call(axisB)
.attr('transform', `translate(0, ${y(zeroAxis)})`)
.append('text')
.text(axisX === "date" ? axisX : `${cumulative ? 'cumulative' : 'daily'} ${axisX}`)
.attr('fill', `currentColor`)
.attr('text-anchor', 'end')
.attr('transform', `translate(${x.range()[1]}, ${-2})`);
axis
.append("g")
.call(axisL)
.attr('transform', `translate(${x.range()[0]}, 0)`)
.append("text")
.text(`${cumulative ? 'cumulative' : 'daily'} ${axisY}`)
.attr("fill", `currentColor`)
.attr("text-anchor", `start`)
.attr("transform", `translate(${2}, ${y.range()[1]})`);
const tooltip = svg.append('g');
const xy = [];
circles.each(function() {
xy.push([+this.getAttribute("cx"), +this.getAttribute("cy") + 2]);
});
const delaunay = d3.Delaunay.from(xy);
const numformat = d3.format(',d');
svg.on('touchmove mousemove', function() {
const m = d3.mouse(this),
i = delaunay.find(...m),
dist = Math.hypot(m[0] - xy[i][0], m[1] - xy[i][1]),
d = circles.data()[i];
if (dist < 10)
tooltip.attr("transform", `translate(${xy[i]})`).call(
callout,
`${groupBy === 'total' ? 'Total' : d[1][groupBy]}
${d[0]}
cases: ${numformat(d[1].cases)}
deaths: ${numformat(d[1].deaths)}`
);
else tooltip.call(callout, null);
});
svg.on('touchend mouseleave', () => tooltip.call(callout, null));
}