function makeChart({
data,
format,
color,
colTitle,
title,
type_ = "Display",
colorScale,
pointer,
xBuffer = 175 / 954
}) {
const barHeight = (35 / 954) * width;
const titleSize = pxToVw(16.5);
const header = type_ === "Display" ? "Zone" : "Team";
const dataWithZone = [{ name: header, value: 0 }].concat(data);
const height =
Math.ceil((data.length + 0.1) * barHeight) + margin.top + margin.bottom;
const x = d3
.scaleLinear()
.domain(d3.extent(dataWithZone, d => d.value))
.rangeRound([margin.left + xBuffer * width, width - margin.right]);
const svg = d3.create("svg").attr("viewBox", [0, 0, width, height]);
function fillFunction(d) {
if (colorScale) return colorScale(d.value);
if (type_ === "Display") return color;
else return d.name.includes("Bucks") ? "darkgreen" : "#94ae83";
}
const y = d3
.scaleBand()
.domain(d3.range(dataWithZone.length))
.range([margin.top, height - margin.bottom])
.paddingInner(.4);
const yAxis = g =>
g
.attr("transform", `translate(${margin.left},0)`)
.call(
d3
.axisLeft(y)
.tickSize(0)
.tickFormat(i => dataWithZone[i].name)
)
.selectAll("text")
.attr("dy", "0.785em")
.attr("text-anchor", "start");
const rect = svg
.append("g")
.selectAll("rect")
.data(dataWithZone)
.join("rect")
.attr("fill", d => fillFunction(d))
.attr("x", d => x(Math.min(d.value, 0)))
.attr("y", (_, i) => y(i) + (y.step() - y.bandwidth()) / 2)
.attr("width", d => Math.abs(x(d.value) - x(0)))
.attr("height", y.bandwidth())
.attr("id", d => d.name)
.attr("opacity", ".8")
.attr("style", `cursor: ${pointer}`);
svg
.append("g")
.attr("font-family", "sans-serif")
.selectAll("text")
.data(dataWithZone)
.join("text")
.attr("text-anchor", d => (d.value < 0 ? "end" : "start"))
.attr("x", (d, i) => {
if (i === 0) return x(0) + 1;
return x(d.value) + Math.sign(d.value - 0) * 4;
})
.attr("y", (d, i) => y(i) + y.step() / 2)
.attr("dy", "0.35em")
.attr("font-size", (d, i) => (i === 0 ? titleSize : pxToVw(14)))
.attr("font-weight", (d, i) => {
if (i === 0) return "bold";
})
.text((d, i) => {
if (i > 0) return format(d.value);
else return colTitle;
});
svg
.append("g")
.selectAll("line")
.data(dataWithZone)
.join("line")
.attr("x1", x.range()[0] - xBuffer * width)
.attr("x2", x.range()[1])
.attr("y1", (d, i) => y(i) + y.step())
.attr("y2", (d, i) => y(i) + y.step())
.attr("style", "stroke: lightgrey; stroke-width: 1.5px; opacity: .25");
const zeroValue = d3.line()([
[x(0), y(0) + y.step()],
[x(0), y(dataWithZone.length - 1) + y.step()]
]);
svg
.append("g")
.append("path")
.attr("d", zeroValue)
.attr("style", "stroke: lightgrey; stroke-width: 2.5px");
svg
.append("g")
.call(yAxis)
.call(g => g.select(".domain").remove())
.selectAll("text")
.attr("font-size", (d, i) => (i === 0 ? titleSize : pxToVw(15)))
.attr("font-weight", (d, i) => {
if (i === 0) return "bold";
});
const chart = svg.node();
let titleDiv = `<div/>`;
if (title)
titleDiv = `<div style="text-align: center; font-family: sans-serif; font-size: ${pxToVw(
16.5
)}; font-weight: 700" >${title}</div>`;
const container = html`
${titleDiv}
${chart}
<figcaption style="margin-top: 5px">Data from <a href="http://www.stats.nba.com">stats.nba.com</href></figcaption>
</div>`;
container.value = null;
rect
.on('mouseover', function() {
d3.select(this).attr('opacity', '1');
container.value = d3.select(this).attr("id");
container.dispatchEvent(new CustomEvent("input"));
})
.on('mouseout', function(d, i) {
d3.select(this).attr('opacity', '.8');
container.value = null;
container.dispatchEvent(new CustomEvent("input"));
});
return container;
}