task_4_solution = {
const width = 600;
const height = 500;
const margin = 30;
const cScale = (t) => d3.interpolateRdBu(t);
const svg = d3.create("svg").attr("viewBox", [0, 0, width, height]);
const xScale = d3
.scaleBand()
.domain(dataBaseline.map((d) => d.month))
.range([margin, width - margin]);
const yearArr = [...new Set(data.map((d) => d.year))];
const singleRectScale = d3.scaleBand().domain(yearArr).range([0, height]);
const yScale = d3
.scaleBand()
.domain(yearArr)
.range([margin, height - margin]);
const convNumToMonth = (d) => dataBaseline[d.month - 1].month;
const absolValues = data.map(
(d) => d.anomaly + dataBaseline[d.month - 1].temp
);
const colourValueConv = (d) =>
1 - (d - d3.min(absolValues)) / (d3.max(absolValues) - d3.min(absolValues));
let chosen = 0;
// );
// else if (currAbsVal > chosen)
// return (
// 0.5 - ((currAbsVal - chosen) / (d3.max(absolValues) - chosen)) * 0.5
// );
// else return 0.5;
// }
const average = (d3.max(absolValues) + d3.min(absolValues)) / 2;
function newColourValue(chosen, currAbsVal) {
let mean = Math.abs(average - chosen);
let minRange = d3.min(absolValues);
let maxRange = d3.max(absolValues);
if (chosen > average) maxRange += mean * 2;
else if (chosen < average) minRange -= mean * 2;
return 1 - (currAbsVal - minRange) / (maxRange - minRange);
}
function update() {
svg
.selectAll("rect")
.data(data)
.join(
(enter) =>
enter
.append("rect")
.attr("class", "year-rect")
.attr("x", (d) => xScale(convNumToMonth(d)))
.attr("width", xScale.bandwidth())
.attr("y", (d) => yScale(d.year))
.attr("height", (d) => yScale.bandwidth())
.attr("year", (d) => d.year)
.on("mouseover", function (d) {
d3.select(this).attr("stroke", "black");
svg
.append("text")
.attr("fill", "black")
.attr("text-anchor", "middle")
.attr("x", margin / 2)
.attr("y", (e) => parseInt(this.getAttribute("y")))
.attr("dy", ".5em")
.attr("class", "yearLabel")
.attr("font-size", "12px")
.text(this.getAttribute("year"));
})
.on("mouseout", function () {
d3.select(this).transition().attr("stroke", "none");
d3.selectAll(".yearLabel").remove();
})
.on("click", function (eventObject, datum) {
chosen = absolValues[data.findIndex((d) => d == datum)];
update(); // Call update() again to modify the appearance of the appended rects
}),
(update) => update
)
.transition()
.attr("fill", (d, i) => {
if (chosen == 0) return cScale(colourValueConv(absolValues[i]));
else return cScale(newColourValue(chosen, absolValues[i]));
});
}
update(); // The first call of update() appends the rects
const xAxis = d3.axisBottom().scale(xScale);
svg
.append("g")
.attr("class", "x-axis")
.call(xAxis)
.attr("transform", `translate(0, ${height - margin})`);
return svg.node();
}