customScroller8 = {
const width = window.innerWidth;
const height = 850;
const margin = {top: 10, right: 0, bottom: 30, left: 0};
const colors = {
"Drama": "#7B3F74",
"Comedy": "#FF5F1F"
}
const div = html`<div></div>`;
const initialYear = 2000;
const initialData = [
{ name: "Drama", value: 25 },
{ name: "Comedy", value: 25 }
];
const chartWidth = width - margin.left - margin.right;
const chartHeight = height - margin.top - margin.bottom;
const x = d3.scaleBand()
.domain(initialData.map(d => d.name))
.range([chartWidth / 3, width - chartWidth / 3])
.padding(0.25);
const y = d3.scaleLinear()
.domain([0, 25])
.range([0, chartHeight]);
const xAxis = d3.axisBottom(x).ticks(2);
const blockHeight = 25;
const blockGap = 5;
const offSet = {
"Drama": - 2 * x.bandwidth() / 2,
"Comedy": x.bandwidth() / 3
};
const divSel = d3.select(div)
.style("overflow-y", "auto")
.style("max-width", `${width}px`)
.style("max-height", `${height}px`)
.style("border", "1px solid #ccc");
const svg = divSel.append("svg")
.attr("width", width)
.attr("height", height)
.style("position", "absolute")
.style("top", "0px")
.style("left", "0px")
.style("pointer-events", "none");
const chartGroup = svg.append("g")
.attr("transform", `translate(${margin.left}, ${margin.top})`);
[5, 10, 15, 20, 25].forEach(refVal => {
const y_val = chartHeight - (blockHeight + blockGap) * refVal - 2.5;
chartGroup.append("line")
.attr("x1", width / 2 + offSet["Drama"])
.attr("x2", width / 2 + 2.5 * offSet["Comedy"])
.attr("y1", y_val)
.attr("y2", y_val)
.attr("stroke", "#999")
.attr("stroke-dasharray", "4 2")
.attr("stroke-width", 1)
.lower();
chartGroup.append("text")
.attr("x", chartWidth/2 - 10) // center within chartGroup
.attr("y", y_val - 5) // nudge up slightly for spacing
.attr("text-anchor", "middle")
.style("font", "16px")
.style("fill", "#666")
.text(`${refVal} episodes`);
});
const referenceBlocksGroup = chartGroup.selectAll(".reference-group")
.data(initialData)
.enter()
.append("g")
.attr("class", "reference-group")
.attr("transform", d => `translate(0, 0)`);
referenceBlocksGroup.each(function(d) {
const group = d3.select(this);
group.selectAll("rect")
.data(d3.range(d.value)) // create an array [0, 1, ..., value-1]
.enter()
.append("rect")
.attr("x", width / 2 + offSet[d.name])
.attr("y", (d, i) => chartHeight - (i + 1) * (blockHeight + blockGap))
.attr("width", x.bandwidth() / 2)
.attr("height", blockHeight)
.attr("fill", "#d3d3d3");
});
const blocksGroup = chartGroup.selectAll(".block-group")
.data(initialData)
.enter()
.append("g")
.attr("class", "block-group")
.attr("transform", d => `translate($0, 0)`);
const yearLabel = svg.append("text")
.attr("x", width / 2 - 10)
.attr("y", margin.top * 3)
.attr("text-anchor", "middle")
.style("fill", "#666")
.style("font", "32px serif")
.style("font-weight", "bold");
const bestDrama = svg.append("text")
.attr("x", width / 2 + offSet["Drama"] + x.bandwidth() / 4)
.attr("y", height - margin.bottom / 2)
.attr("text-anchor", "middle")
.style("fill", "#666")
.style("font", "20px serif")
.style("font-weight", "bold")
.text("Best drama");
const bestComedy = svg.append("text")
.attr("x", width / 2 + offSet["Comedy"] + x.bandwidth() / 4)
.attr("y", height - margin.bottom / 2)
.attr("text-anchor", "middle")
.style("fill", "#666")
.style("font", "20px serif")
.style("font-weight", "bold")
.text("Best comedy");
const bestDramaName = svg.append("text");
const bestComedyName = svg.append("text");
// const title = svg.append("text")
// .attr("x", width / 2 - 10)
// .attr("y", 40)
// .attr("text-anchor", "middle")
// .style("fill", "#666")
// .style("font", "32px serif")
// .text("Over the years, Emmy Awards have gone to TV seasons with fewer episodes");
const nSteps = 27;
const stepSize = 300;
const scrollHeight = stepSize * nSteps;
const innerDiv = divSel.append("div")
.style("width", `${width}px`)
.style("height", `${scrollHeight}px`);
const updateBars = (year) => {
const newData = [
{ name: "Drama", value: showDataByYear[year]?.drama_episodes || 0 },
{ name: "Comedy", value: showDataByYear[year]?.comedy_episodes || 0 }
];
yearLabel.text(`${year}`);
const blocks = chartGroup.selectAll(".block-group")
blocks.data(newData, d => d.name); // key by genre
blocks.enter()
.append("g")
.attr("class", "block-group")
.attr("transform", d => `translate(0, 0)`)
.merge(blocks)
.each(function(d) {
const group = d3.select(this);
// JOIN
const rects = group.selectAll("rect")
.data(d3.range(d.value));
// EXIT
rects.exit().remove();
// UPDATE + ENTER
rects.enter()
.append("rect")
.merge(rects)
.attr("x", width / 2 + offSet[d.name])
.attr("y", (d, i) => chartHeight - (i + 1) * (blockHeight + blockGap))
.attr("width", x.bandwidth() / 2)
.attr("height", blockHeight)
.attr("fill", colors[d.name])
.attr("opacity", d.value/25);
});
bestComedyName
.attr("x", 10 + width / 2 + offSet["Comedy"] + x.bandwidth() / 2)
.attr("y", chartHeight - (newData[1].value - 1) * (blockHeight + blockGap))
.text(`${showDataByYear[year].comedy_show_name}, Season ${showDataByYear[year].comedy_season_number}`)
.style("fill", "#666")
.style("font", "24px serif")
.style("font-weight", "bold");
bestDramaName
.attr("x", width / 2 + offSet["Drama"] - 10)
.attr("y", chartHeight - (newData[0].value - 1) * (blockHeight + blockGap))
.text(`${showDataByYear[year].drama_show_name}, Season ${showDataByYear[year].drama_season_number}`)
.style("fill", "#666")
.attr("text-anchor", "end")
.style("font", "24px serif")
.style("font-weight", "bold");
blocks.exit().remove();
};
let pos = 0;
let currentStep = 0;
divSel.on("scroll", function() {
const newPos = divSel.property("scrollTop");
const newStep = Math.floor(newPos / stepSize);
const year = initialYear + newStep;
if (newStep !== currentStep) {
currentStep = newStep;
updateBars(year);
}
pos = newPos;
});
// Initial render
updateBars(initialYear);
return div;
}