Published
Edited
Sep 19, 2021
Fork of Simple D3
1 fork
4 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
{
const svg = d3
.create("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom);
const scaleHeight = d3
.scaleSymlog() // most similar scale to the original
.domain([0, d3.max(years, (d) => d.count)])
.range([height, 0]);

// GRADIENT
const defs = svg.append("defs");
const gradient = defs
.append("linearGradient")
.attr("id", "gradient")
.attr("gradientUnits", "userSpaceOnUse")
.attr("x1", 0)
.attr("y1", height)
.attr("x2", 0)
.attr("y2", margin.top);
gradient
.append("stop")
.attr("class", "start")
.attr("offset", "0%")
.attr("stop-color", colours.bottom) // bottom gradient
.attr("stop-opacity", 1);
gradient
.append("stop")
.attr("class", "end")
.attr("offset", "100%")
.attr("stop-color", colours.top) // top gradient
.attr("stop-opacity", 1);

// YEAR SELECTION CIRCLES
const yearBalls = d3
.extent(years, (d) => d.key)
.map((d) => ({ x: scaleBand(d) + scaleBand.bandwidth() / 2, y: height }));

// DRAW INSIDE MARGINS
const g = svg
.append("g")
.attr("class", "chart")
.attr("transform", `translate(${margin.left},${margin.top})`);

// BAR CHART
g.selectAll("rect")
.data(years)
.join("rect")
.attr("width", scaleBand.bandwidth)
.attr("height", (d) => height - scaleHeight(d.count))
.attr("y", (d) => scaleHeight(d.count))
.attr("x", (d, i) => scaleBand(d.key))
.attr("fill", "url(#gradient)");

const grayLine = g
.append("path")
.attr(
"d",
d3.line()([
[0, height],
[width, height]
])
)
.attr("stroke-width", 2)
.attr("opacity", 1)
.attr("stroke", "#C1C5C7");

const blueLine = g
.append("path")
.attr("class", "blueline")
.attr("d", d3.line()(yearBalls.map((d) => [d.x, d.y])))
.attr("stroke-width", 2)
.attr("stroke", colours.accent);

const yearPicker = g.selectAll("g").data(yearBalls).join("g");

yearPicker.call(
d3
.drag()
.on("drag", function dragged(event, d) {
const year = scaleBalls(event.x).key;
const xAxisValue = scaleBand(year) + scaleBand.bandwidth() / 2;
// move the circle
d3.select(this)
.select("circle")
.attr("cx", (d.x = xAxisValue));
// move the blue line
g.select(".blueline").attr(
"d",
d3.line()(yearBalls.map((d) => [d.x, d.y]))
);
// change the text
d3.select(this)
.select("text")
.attr("x", (d) => xAxisValue)
.text((d) => year);
// colour the bars
g.selectAll("rect").attr("fill", (d) => {
const years = yearBalls.map((d) => scaleBalls(d.x).key);
if (d.key < d3.min(years) || d.key > d3.max(years)) return "#E3E3E3";
return "url(#gradient)";
});
})
.on("end", () => {
console.log(d3.sort(yearBalls.map((d) => scaleBalls(d.x).key)));
})
);

yearPicker
.append("circle")
.attr("cx", (d) => d.x)
.attr("cy", (d) => d.y)
.attr("r", 9)
.attr("fill", "white")
.attr("stroke-width", 2)
.attr("stroke", colours.accent)
.attr("style", "cursor: pointer");

yearPicker
.attr("text-anchor", "middle")
.attr("font-family", "Roboto, Arial, sans-serif")
.attr("font-size", "12px")
.append("text")
.attr("y", (d) => d.y + margin.bottom / 2)
.attr("x", (d) => d.x)
.attr("fill", colours.accent)
.text((d) => scaleBalls(d.x).key);

return svg.node();
}
Insert cell
Insert cell
colours = new Object({
top: "#37474f",
bottom: "#546e7a",
accent: "#263238"
})
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more