chart = {
const svg = d3.create("svg")
.attr("width", width)
.attr("height", height)
.attr("viewBox", [0, 0, width, height])
.attr("style", "max-width: 100%; height: auto; background: #006d77; color: #fff;")
.attr("class", "chart");
const rectWidth = 100
svg.append('g')
.append('text')
.attr('class', 'chart-title')
.attr('x', width / 2)
.attr('y', margin.top/2)
.attr('text-anchor', 'middle')
.attr('fill', 'white')
.attr('style', 'font-size: 24px;')
.text("Stacked & Labeled Bar Chart");
svg.append('g').call(yGrid)
const rects = svg.append("g").selectAll().data(stack).enter()
.append("g")
.attr("fill", d => colors[d.key]);
rects.selectAll("rect")
.data(d => d)
.join("rect")
.attr("x", (d) => xScale(d.data.date) - rectWidth/2)
.attr("y", (d) => yScale(d[1]))
.attr("height", d=> yScale(d[0]) - yScale(d[1]))
.attr("width", rectWidth);
// Add text labels
rects.selectAll("text")
.data(d => d)
.join("text")
.attr("x", (d) => xScale(d.data.date))
.attr("y", (d) => yScale(d[0]) + (yScale(d[1]) - yScale(d[0])) / 2) // center text
.attr("text-anchor", "middle")
.attr("alignment-baseline", "middle")
.attr("fill", "#006d77")
.attr("opacity", (d) => yScale(d[1]) ? 1 : 0) // don't show text labels for segments that don't exist in a given month (i.e. there's no "Hold" in May so we don't want to show a text element that says "NaN")
.text((d) => (d[1] - d[0]));
// Add the x-axis and label.
svg.append("g")
.attr("transform", `translate(0,${height - margin.bottom})`)
.call(
d3.axisBottom(xScale)
.tickFormat(d3.timeFormat('%b')) // month abbr. formatting
.tickSize(0) // hide tick marks
.tickPadding(10)
)
.selectAll(".domain,.tick>line") // hide x axis line
.remove();
// Add the y-axis and label, and remove the domain line.
svg.append("g")
.attr("transform", `translate(${margin.left},0)`)
.call(d3.axisLeft(yScale)
.ticks(8)
.tickSize(0) // hide tick marks
)
.attr("font-size", "20px")
.selectAll(".domain,.tick>line") // hide y axis line
.remove();
// Add tick label styling
svg.selectAll(".tick text")
.attr("font-size", "20px")
const legendKeys = Object.keys(colors).reverse()
// Add legend
svg.selectAll("legend-marks")
.data(legendKeys)
.enter()
.append("rect")
.attr("x", 100)
.attr("y", function(d,i){ return height - 50 - i*(25)}) // 100 is where the first dot appears. 25 is the distance between dots
.attr("width", 20)
.attr("height", 20)
.style("fill", (d)=>colors[d])
// Add one dot in the legend for each name.
svg.selectAll("legend-labels")
.data(legendKeys)
.enter()
.append("text")
.attr("x", 100 + 20*1.2)
.attr("y", function(d,i){ return height - 50 - i*(20+5) + (20/2)}) // 100 is where the first dot appears. 25 is the distance between dots
.style("fill", "#fff")
.text((d)=>d)
.attr("text-anchor", "left")
.style("alignment-baseline", "middle")
// Return the SVG element.
return svg.node();
}