chart = {
const cx = width / 2;
const cy = height / 2;
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height])
.attr("font-family", "sans-serif")
.attr("font-size", 10)
.attr("text-anchor", "middle")
.attr("fill", "currentColor")
.style("margin", "0 -14px")
.style("display", "block");
svg.append("path")
.attr("d", path(graticule))
.attr("fill", "none")
.attr("stroke", "currentColor")
.attr("stroke-opacity", 0.2);
svg.append("path")
.attr("d", path(outline))
.attr("fill", "none")
.attr("stroke", "currentColor");
svg.append("g")
.call(xAxis);
svg.append("g")
.call(yAxis);
const sunPath = svg.append("path")
.attr("fill", "none")
.attr("stroke", "red")
.attr("stroke-width", 2);
const hour = svg.append("g")
.selectAll("g")
.data(d3.range(24))
.join("g");
hour.append("circle")
.attr("fill", "black")
.attr("r", 2);
hour.append("text")
.attr("dy", "-0.4em")
.attr("stroke", "white")
.attr("stroke-width", 4)
.attr("stroke-linejoin", "round")
.attr("fill", "none")
.clone(true)
.attr("stroke", null)
.attr("fill", "black");
function update(date) {
sunPath.attr("d", path({type: "LineString", coordinates: d3.utcMinutes(date, d3.utcDay.offset(date)).map(solar.position)}));
hour.data(d3.utcHours(date, d3.utcDay.offset(date)));
hour.attr("transform", d => `translate(${projection(solar.position(d))})`);
hour.select("text:first-of-type").text(formatHour);
hour.select("text:last-of-type").text(formatHour);
}
return Object.assign(svg.call(update).node(), {update});
}