chart = {
const svg = d3.select(DOM.svg(width, h))
.classed("crashes-heatmap", true)
const defs = svg.append("defs");
const linearGradient = defs.append("linearGradient")
.attr("id", "linear-gradient");
linearGradient.selectAll("stop")
.data(color.ticks().map((t, i, n) => ({ offset: `${100*i/n.length}%`, color: color(t) })))
.enter().append("stop")
.attr("offset", d => d.offset)
.attr("stop-color", d => d.color);
const g = svg.append("g")
.attr("transform", `translate(${margin.left}, ${margin.top})`)
g.selectAll("rect")
.data(data)
.enter().append("rect")
.attr("x", d => d.Month * gridSize)
.attr("y", d => d.Timezone * gridSize)
.attr("width", gridSize)
.attr("height", gridSize)
.attr("fill", d => color(d.Value))
.attr("stroke", "#e2e2e2")
g.selectAll("text")
.data(data)
.enter()
.append("text")
.attr("x", d => d.Month * gridSize + gridSize/2)
.attr("y", d => d.Timezone * gridSize + gridSize/2)
.style("text-anchor", "middle")
.attr("dy", ".35em")
.text(d => formatValue(d.Value))
g.selectAll(".timezone")
.data(Timezone)
.enter().append("text")
.text(d => d)
.classed("timezone", true)
.attr("x", 0)
.attr("y", (d, i) => i * gridSize)
.style("text-anchor", "end")
.attr("transform", "translate(-6," + gridSize / 1.8 + ")")
g.selectAll(".month")
.data(months)
.enter().append("text")
.text(d => d)
.classed("month", true)
.attr("x", (d, i) => i * gridSize)
.attr("y", 0)
.style("text-anchor", "middle")
.attr("transform", "translate(" + gridSize / 2 + ", -6)");
g.append("g")
.call(legend)
return svg.node();
}