chart_2 = {
const width = 1000;
const height = 600;
const marginRight = 20;
const marginLeft = 20;
const marginBottom = 20;
const popScale = 2;
const marginTop = 60;
const radius = 16;
const padding = 7;
const x = d3
.scaleLinear()
.domain(d3.extent(sk, (d) => d["total_weeks"]))
.range([marginLeft, width - marginRight]);
const svg = d3
.create("svg")
.attr("width", width)
.attr("height", height)
.attr("viewBox", [0, 0, width, height])
.style("background-color", "white")
.attr("style", "max-width: 100%; height: auto;");
svg
.append("rect")
.attr("width", width)
.attr("height", height)
.attr("fill", "white");
svg
.append("text")
.attr("x", width / 2)
.attr("y", marginTop / 1.5) // Positioning the title halfway through the top margin
.attr("text-anchor", "middle") // This will center the text at the specified (x, y)
.style("font-size", "45px")
.style("font-family", "Nosifer") // Adjust font size as needed
.style("fill", "#c81d25") // Adjust text color as needed
.text("The Master of Macabre");
// Append subtitle
svg
.append("text")
.attr("x", width / 2)
.attr("y", (marginTop / 4) * 5.3) // Positioning the subtitle a bit lower than the title
.attr("text-anchor", "middle") // This will center the text at the specified (x, y)
.style("font-size", "25px") // Adjust font size as needed
.style("fill", "#c81d25") // Adjust text color as needed
.style("font-family", "Josefin Sans")
.text("Stephen King’s Weeks on the New York Times Bestseller List");
// Add the x axis with modified color
const xAxis = svg
.append("g")
.attr("transform", `translate(0,${height - marginBottom})`)
.call(d3.axisBottom(x).tickSizeOuter(0));
// Change the color of the x-axis line to white
xAxis.select(".domain").attr("stroke", "black");
// Change the color of the ticks to white
xAxis.selectAll(".tick line").attr("stroke", "black");
// Change the color of the tick labels (text) to white
xAxis
.selectAll(".tick text")
.attr("fill", "black")
.style("font-family", "Josefin Sans") // Set the font family
.style("font-size", "12px") // Set the font size
.style("font-weight", "bold");
// Append x-axis title
xAxis
.append("text")
.attr("class", "x-axis-label")
.attr("text-anchor", "end") // To align the text at the end of the axis
.attr("x", width - marginRight) // Position at the end of the x-axis
.attr("y", -10) // Position above the axis line, adjust as needed
.style("fill", "black") // Text color
.style("font-family", "Josefin Sans")
.style("font-weight", "bold")
.text("Number of Weeks on Bestseller List ➡");
// Processed data from dodge function
const processedData = dodge(sk, {
radius: radius * 2 + padding,
x: (d) => x(d["total_weeks"])
});
// Create group elements for each data point
const groups = svg
.selectAll("g.data-point")
.data(processedData)
.enter()
.append("g")
.attr("class", "data-point")
.on("mouseover", handleMouseOver)
.on("mouseout", handleMouseOut);
// Append circles inside each group
groups
.append("circle")
.attr("cx", (d) => d.x)
.attr("cy", (d) => height / 2 - radius - padding - d.y)
.attr("r", radius)
.attr("stroke", "#c81d25")
.attr("stroke-width", 3);
// Append images inside each group
groups
.append("image")
.attr("xlink:href", (d) => d.data.image_url)
.attr("x", (d) => d.x - radius)
.attr("y", (d) => height / 2 - radius - padding - d.y - radius)
.attr("width", radius * 2)
.attr("height", radius * 2)
.attr(
"clip-path",
"circle(" + radius + "px at " + radius + "px " + radius + "px)"
)
.attr("preserveAspectRatio", "xMidYMid slice");
const tooltip = d3
.select("body")
.append("div")
.attr("class", "tooltip")
.style("background", "#c81d25")
.style("opacity", 0.8)
.style("border-radius", "5px")
.style("padding", "10px")
.style("color", "white")
.style("font-family", "Josefin Sans")
.style("position", "absolute")
.style("text-align", "center")
.style("visibility", "hidden");
// Function to handle mouseover event
function handleMouseOver(event, d) {
const x = event.pageX;
const y = event.pageY;
const element = d3.select(this);
// Calculate the center of the circle
const centerX = d.x;
const centerY = height / 2 - radius - padding - d.y;
// Set the tooltip content with year above the title
tooltip
.html(`<strong>${d.data.year}</strong><br>${d.data.title}`) // Combining year and title
.style("visibility", "visible")
.style("left", `${x}px`)
.style("top", `${y}px`);
element
.selectAll("circle, image")
.raise() // Bring the element to the top in the SVG stacking context
.transition()
.duration(200)
// Scale around the center of the circle
.attr(
"transform",
`translate(${centerX},${centerY}) scale(${popScale}) translate(${-centerX},${-centerY})`
);
}
// Function to handle mouseout event
function handleMouseOut(event, d) {
const element = d3.select(this);
// Calculate the center of the circle
const centerX = d.x;
const centerY = height / 2 - radius - padding - d.y;
tooltip.style("visibility", "hidden");
element
.selectAll("circle, image")
.transition()
.duration(200)
// Scale back to normal around the center of the circle
.attr(
"transform",
`translate(${centerX},${centerY}) scale(1) translate(${-centerX},${-centerY})`
);
}
// Optionally, create a clipping path for circular images
svg
.append("defs")
.append("clipPath")
.attr("id", "circle-clip")
.append("circle")
.attr("cx", radius)
.attr("cy", radius)
.attr("r", radius);
return svg.node();
}