figureChart = {
const highlightColor = "#47A8BD"
const unhighlightColor = "#ddd"
const AVGcolor = "#d62728"
const stationColor = "yellow"
const points = data[averageCall(rollingAverage)].map((d) => [scalex(d[rollingAverage]), scaley(d[options]), d["Station Name"]]);
const groups = d3.rollup(points, v => Object.assign(v, {z: v[0][2]}), d => d[2]);
const rollupEVdata = Array.from(d3.rollup(data[averageCall(rollingAverage)], v => d3.mean(v, d => d[options]), d => d[rollingAverage]), ([rollingAverage, mean]) => ({rollingAverage, mean})).sort((a, b) => d3.ascending(a.rollingAverage, b.rollingAverage))
const parent = d3.create("div");
const totalSVG = parent.append("svg")
.attr("width", width)
.attr("height", height)
.style("position", "absolute")
.style("pointer-events", "none")
.style("z-index", 1)
const yAxis = totalSVG.append("g")
.attr("transform", `translate(${margins.marginLeft},0)`)
.call(d3.axisLeft(scaley))
.call(g => g.select(".domain").remove())
.call(g => g.selectAll(".tick line").clone()
.attr("x2", width - margins.marginLeft - margins.marginRight)
.attr("stroke-opacity", 0.1))
.call(g => g.append("text")
.attr("x", -margins.marginLeft)
.attr("y", 10)
.attr("fill", "currentColor")
.attr("text-anchor", "start")
.text(`↑ ${options}`))
// Create a scrolling div containing the area shape and the horizontal axis.
const body = parent.append("div")
.style("overflow-x", "scroll")
.style("-webkit-overflow-scrolling", "touch");
const svg = body.append("svg")
.attr("width", totalWidth)
.attr("height", height)
.style("display", "block")
// Add the horizontal axis.
const xAxis = svg.append("g")
.attr("transform", `translate(0, ${height - margins.marginBottom})`)
.call(rollingAverage == "StartDate"? d3.axisBottom(scalex).ticks(width / 40).tickSizeOuter(0): d3.axisBottom(scalex).ticks(width / 100).tickSizeOuter(0).tickFormat(d3.format(".0f")))
// Draw the lines.
const line = d3.line().curve(d3[curve])
const path = svg.append("g")
.attr("fill", "none")
.attr("stroke", aggToggle ? unhighlightColor : highlightColor)
.attr("stroke-width", 1)
.attr("stroke-linejoin", "round")
.attr("stroke-linecap", "round")
.selectAll("path")
.data(groups.values())
.join("path")
.style("mix-blend-mode", "multiply")
.attr("d", line);
// Draw the aggregate line
const lineAgg = d3.line().curve(d3[curve])
.x(d => scalex(d.rollingAverage))
.y(d => scaley(d.mean))
// Append a path for the line.
const aggPath = svg.append("path")
.attr("fill", "none")
.attr("stroke", AVGcolor)
.attr("stroke-width", aggToggle ? 2 : 0)
.attr("d", lineAgg(rollupEVdata))
.attr("opacity", 0.8)
// Add an invisible layer for the interactive tip.
const dot = svg.append("g")
.attr("display", "none");
dot.append("circle")
.attr("r", 2.5);
dot.append("text")
.attr("text-anchor", "middle")
.attr("y", -8);
svg
.on("pointerenter", pointerentered)
.on("pointermove", pointermoved)
.on("pointerleave", pointerleft)
.on("touchstart", event => event.preventDefault());
yield parent.node();
// Initialize the scroll offset after yielding the chart to the DOM.
body.node().scrollBy(totalWidth, 0);
// When the pointer moves, find the closest point, update the interactive tip, and highlight
// the corresponding line. Note: we don't actually use Voronoi here, since an exhaustive search
// is fast enough.
function pointermoved(event) {
const [xm, ym] = d3.pointer(event);
const i = d3.leastIndex(points, ([x, y]) => Math.hypot(x - xm, y - ym));
const [x, y, k] = points[i];
path.style("stroke", ({z}) => z === k ? highlightColor : unhighlightColor).filter(({z}) => z === k).raise();
dot.attr("transform", `translate(${x},${y})`);
dot.select("text").text(k).attr("font-size", 12).attr("font-weight", 5)
svg.property("value", data[averageCall("year")][i]).dispatch("input", {bubbles: true});
}
function pointerentered() {
path.style("mix-blend-mode", null).style("stroke", unhighlightColor);
dot.attr("display", null);
}
function pointerleft() {
path.style("mix-blend-mode", "multiply").style("stroke", null);
dot.attr("display", "none");
svg.node().value = null;
svg.dispatch("input", {bubbles: true});
}
}