-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlevel1.js
More file actions
181 lines (151 loc) · 6.69 KB
/
level1.js
File metadata and controls
181 lines (151 loc) · 6.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
console.log("Level 1 script is running");
// Function to initialize Level 1 (Heatmap)
function initializeLevel1() {
// Clear previous content
document.getElementById("level1-container").innerHTML = "";
// Set up dimensions
const width1 = 900, height1 = 500, margin1 = { top: 80, right: 40, bottom: 50, left: 100 };
// Create Title
d3.select("#level1-container").append("h2")
.text("Year/Month Heatmap")
.style("text-align", "center")
.style("margin-bottom", "10px");
// Create Toggle Button for Max/Min Temperature
const toggleButton1 = d3.select("#level1-container").append("button")
.text("Show: Min Temperature")
.style("display", "block")
.style("margin", "10px auto")
.style("padding", "10px")
.style("font-size", "14px")
.style("cursor", "pointer");
let tempType1 = "max"; // Default to Max Temperature
// Create Legend SVG (Centered Above Heatmap)
const legendSvg1 = d3.select("#level1-container").append("svg")
.attr("width", 600)
.attr("height", 50)
.style("display", "block")
.style("margin", "0 auto 10px");
// Create Heatmap SVG
const svg1 = d3.select("#level1-container").append("svg")
.attr("width", width1)
.attr("height", height1);
// Create Tooltip in <body>
const tooltip1 = d3.select("body")
.append("div")
.attr("id", "tooltip")
.style("position", "absolute")
.style("visibility", "hidden")
.style("background", "rgba(0, 0, 0, 0.85)")
.style("color", "white")
.style("padding", "8px")
.style("border-radius", "5px")
.style("font-size", "12px")
.style("box-shadow", "0px 0px 5px rgba(0,0,0,0.3)")
.style("pointer-events", "none");
// Load CSV Data
d3.csv("temperature_daily.csv").then(data => {
console.log("CSV Loaded");
// Convert Data
data.forEach(d => {
d.date = new Date(d.date);
d.year = d.date.getFullYear();
d.month = d.date.getMonth() + 1;
d.maxTemp = +d.max_temperature;
d.minTemp = +d.min_temperature;
});
// Filter Data (From 1997 onwards)
data = data.filter(d => d.year >= 1997);
// Aggregate Monthly Data
function processData(tempType) {
return d3.rollups(
data,
v => ({
max: d3.max(v, d => d.maxTemp),
min: d3.min(v, d => d.minTemp)
}),
d => d.year,
d => d.month
).flatMap(([year, months]) =>
months.map(([month, temps]) => ({ year, month, ...temps }))
);
}
let processedData1 = processData(tempType1);
// Create Scales
const years1 = [...new Set(processedData1.map(d => d.year))].sort();
const months1 = d3.range(1, 13);
const xScale1 = d3.scaleBand().domain(years1).range([margin1.left, width1 - margin1.right]).padding(0.05);
const yScale1 = d3.scaleBand().domain(months1).range([margin1.top, height1 - margin1.bottom]).padding(0.05);
let colorScale1 = d3.scaleSequential(d3.interpolateYlOrRd)
.domain(d3.extent(processedData1, d => d[tempType1]));
// Draw Color Legend (Centered)
function updateLegend1() {
legendSvg1.selectAll("*").remove();
const legendWidth = 500;
const legendGradient = legendSvg1.append("defs").append("linearGradient")
.attr("id", "legend-gradient")
.attr("x1", "0%").attr("x2", "100%");
d3.range(0, 1.05, 0.1).forEach(t => {
legendGradient.append("stop")
.attr("offset", `${t * 100}%`)
.attr("stop-color", colorScale1(colorScale1.domain()[0] + t * (colorScale1.domain()[1] - colorScale1.domain()[0])));
});
legendSvg1.append("rect")
.attr("width", legendWidth)
.attr("height", 10)
.attr("x", (600 - legendWidth) / 2)
.attr("y", 10)
.style("fill", "url(#legend-gradient)");
legendSvg1.append("g")
.attr("transform", `translate(${(600 - legendWidth) / 2}, 30)`)
.call(d3.axisBottom(d3.scaleLinear().domain(colorScale1.domain()).range([0, legendWidth]))
.ticks(5).tickFormat(d => `${Math.round(d)}°C`));
}
updateLegend1();
// Add X & Y Axis
svg1.append("g").attr("transform", `translate(0,${margin1.top - 5})`)
.call(d3.axisTop(xScale1).tickFormat(d3.format("d")));
svg1.append("g").attr("transform", `translate(${margin1.left},0)`)
.call(d3.axisLeft(yScale1).tickFormat(d =>
["January", "February", "March", "April", "May", "June", "July",
"August", "September", "October", "November", "December"][d - 1]
));
// Draw Heatmap
let cells1 = svg1.selectAll(".cell").data(processedData1).join("rect")
.attr("x", d => xScale1(d.year)).attr("y", d => yScale1(d.month))
.attr("width", xScale1.bandwidth()).attr("height", yScale1.bandwidth())
.attr("fill", d => colorScale1(d[tempType1]))
.attr("stroke", "white");
// Add Tooltip Interaction
cells1.on("mouseover", function (event, d) {
tooltip1.style("visibility", "visible")
.html(`
<strong>Date:</strong> ${d.year}-${String(d.month).padStart(2, '0')}<br>
<strong>Max:</strong> ${d.max}°C <br>
<strong>Min:</strong> ${d.min}°C
`);
})
.on("mousemove", function (event) {
tooltip1.style("left", `${event.pageX + 10}px`)
.style("top", `${event.pageY - 40}px`);
})
.on("mouseleave", function () {
tooltip1.style("visibility", "hidden");
});
// Toggle Temperature Type
toggleButton1.on("click", function () {
tempType1 = tempType1 === "max" ? "min" : "max";
toggleButton1.text(`Show: ${tempType1 === "max" ? "Min" : "Max"} Temperature`);
updateHeatmap1();
});
function updateHeatmap1() {
processedData1 = processData(tempType1);
colorScale1.domain(d3.extent(processedData1, d => d[tempType1]));
cells1.data(processedData1)
.transition().duration(800)
.attr("fill", d => colorScale1(d[tempType1]));
updateLegend1();
}
}).catch(error => console.error("CSV Load Failed", error));
}
// Initialize Level 1
initializeLevel1();