Visualize Data with a Heat Map
This is a walkthrough to make a Heat Map project from start to finish. We import some JSON data about global temperatures on land-surface between 1753 and 2015 and render it using the javascript library d3.js.
Notes
1. Project Setup
Looking at what we need to create and talking through the structure of the task.
- Create skeleton page, set title
- Import D3
- Create and link script page
- Create and link stylesheet
- Create svg canvas with id
- Set body display and svg bg
1
2
3
<h1 id="title" class="title">Monthly Global Land-Surface Temperature</h1>
<svg id = 'canvas'></svg>
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
@import url('https://fonts.googleapis.com/css?family=Roboto');
* {
font-family: 'Roboto', sans-serif;
}
html {
min-height: 100%;
}
body {
background-image: radial-gradient( circle 610px at 5.2% 51.6%, rgba(5,8,114,1) 0%, rgba(7,3,53,1) 97.5% );
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
/* height: 100%; */
font-family: 'Roboto', sans-serif;
min-height: 100%;
}
svg {
background-image: radial-gradient( circle 588px at 31.7% 40.2%, rgba(225,200,239,1) 21.4%, rgba(163,225,233,1) 57.1% );
/* background-color: whitesmoke; */
}
2. Creating variables and functions
- url points to JSON File
- xmlrequest is XMLHTTPRequest Used for Importing
- baseTemp will store the base temperature from the response
- data will store array of monthly data
- xScale will be a scale used to create the x-axis
- yScale is used to create y-axis
- canvasDimensiont shows dimensions of the SVG area
- padding will be the padding in the svg canvas
- svg is a d3 selection of the svg area we created for quick access
- drawCanvas() sets the width and height of the svg canvas to what we specified
- generateScales() generates the scales and assigns them to the variables
- drawHeatMap() will draw the rectangular cells
- generateAxes() will draw the X and Y axis on the canvas
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
//Fetch data from the API
let url = 'https://raw.githubusercontent.com/freeCodeCamp/ProjectReferenceData/master/global-temperature.json';
let method = 'GET';
let xmlrequest = new XMLHttpRequest();
//Variables to store fetched data
let baseTemp;
let dataset;
let data = [];
//Create Scales
let xScale;
let yScale;
//Time format
let yearFormat = d3.format('d');
let monthFormat = d3.timeFormat('%B');
//Max and Min
let minYear;
let maxYear;
let minMonth;
let maxMonth;
//Create a tooltip
let tooltip = d3.select('body')
.append('div');
//Create a Canvas
let canvas = d3.select('#canvas')
//Canvas Dimensions
let canvasDimension = {
width: 1300,
height: 600
}
//Legend Dimensions
let legendDimension = {
width: 220,
height: 200
}
//Canvas padding
let padding = {
width: 120,
height: 80
}
3. Fetching JSON Data for visualization
- Open xmlrequest
- Set onload, parse the responsetext and set this to a temporary variable data
- Set the baseTemp variable to a the base temperature from the imported data
- Set values to the array of monthly variance from the imported data
- Log this
- Send the request and see if we have the array
- Draw the canvas first
- Then generate the cells
- Then draw the points
- Then generate the axes
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//Main function
//Fetch Request
xmlrequest.open(method, url, true);
xmlrequest.onload = function(){
dataset = JSON.parse(xmlrequest.responseText);
data = dataset.monthlyVariance;
baseTemp = dataset.baseTemperature;
console.log(data);
console.log(baseTemp);
//Calling canvas function
drawCanvas();
generateScale();
generateAxis();
drawHeatMap();
drawLegend();
drawHint();
}
xmlrequest.send();
Get JSON with the Javascript XMLHTTPRequest Method
4. Adding a title and a description with corresponding ids
- Add title and description tags, set ids, and inner text
- Position all tags
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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Visualize data with a Heat Map</title>
<script src="https://d3js.org/d3.v5.min.js"></script>
<link rel="stylesheet" href="./style.css">
</head>
<body>
<h1 id="title" class="title">Monthly Global Land-Surface Temperature
<div id="description" class="title">1753 - 2015: Average temperature 8.66<strong>℃</strong></div>
</h1>
<svg id = 'canvas'>
</svg>
<svg id="legend">
</svg>
</body>
<script defer src="./script.js"></script>
<script defer src="https://cdn.freecodecamp.org/testable-projects-fcc/v1/bundle.js"></script>
</html>
5. Creating an x-axis that has corresponding id
In generateScales():
- Set xScale to a d3 scaleLinear - years are just integers
- Set the range to make sure the axis exists between padding and width-padding horizontally
1
2
3
xScale = d3.scaleLinear()
.domain([minYear, maxYear + 1])
.range([padding.width, canvasDimension.width - padding.width]);
In generateAxes():
- Create an xAxis which is an axisBottom that uses the xScale
- Create a new group element in the canvas
- Call xAxis to draw the axis in the group element
- Give it an id of ‘x-axis’ as specified
- Give it a transformation of translate by height-padding downwards on y to push it down to the correct position
1
2
3
4
5
6
let xAxis = d3.axisBottom(xScale);
canvas.append('g')
.attr('id', 'x-axis')
.call(xAxis)
.attr('transform', 'translate(0, ' + (canvasDimension.height - padding.height ) + ')');
6. Creating an y-axis that has corresponding id
In generateScales():
- Set yScale to a d3 scaleTime - months are stored as numbers but we will need to display them as strings
- Set the range to make sure the axis exists between padding and height - padding vertically
1
2
3
yScale = d3.scaleTime()
.domain([minMonth, maxMonth])
.range([padding.height, canvasDimension.height - padding.height]);
In generateAxes():
- Create a yAxis which is an axisLeft that uses the yScale
- Create a new group element in the canvas, and use call() to draw the yAxis inside it
- Give it an id of ‘y-axis’ as specified
- Give it a transformation of translate by padding right on x to push it right to align with the x axis
1
2
3
4
5
6
let yAxis = d3.axisLeft(yScale);
canvas.append('g')
.attr('id', 'y-axis')
.call(yAxis)
.attr('transform', 'translate(' + (padding.width) + ', 0)');
7. Creating rectangles with a class of cell that represent the data
In drawHeatMap():
- Select all rectangles in the svg canvas
- Bind them to the values array by calling data()
- Call enter() to specify what to do when there is an array element in no rectangle → All of them in this case
- Use append() to create a new rectangle
- Set the class attribute to ‘cell’ as specified
1
2
3
4
5
canvas.selectAll('rect')
.data(data)
.enter()
.append('rect')
.attr('class', 'cell')
Create a bar for each data point in the set
8. Adding some colors for the cells
In drawHeatMap():
- Call the attribute method on the created rectangle selection and set the ‘fill’ attribute, providing a function that takes in an array item as the second argument
- Create a temporary variable called variance to reference the variance field of each month object
- Return different colors based on the value of variance → blues for lower values, and reds for higher values make sense
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
canvas.selectAll('rect')
.data(data)
.enter()
.append('rect')
.attr('class', 'cell')
.attr('fill', (d) => {
variance = d['variance'];
if (variance <= -1) {
return 'SteelBlue';
} else if (variance <= 0) {
return 'LightSteelBlue';
} else if (variance <= 1) {
return 'Orange';
} else {
return 'Crimson';
}
})
Change color of an SVG element
9. Adding some properties that correspond to month, year and temperature values and making it within the range of the data
On one hand, in drawHeatMap():
- Call the attribute method to create the ‘data-year’, ‘data-month’ and ‘data-temperature’ attributes
- As the second argument, give a function that takes in an item from the array
- For this test, it doesn’t matter what you return, so I just returned item
On the other hand:
- Adapt the attribute methods like so
- Set ‘data-year’ to return the ‘year’ field from the tiem
- Set ‘data-month’ to return the ‘month’ field from the item. You need to subtract 1 because they want it to be in array convention months range from 0 to 11
- Set ‘data-temp’ to return a sum of the baseTemp and variance → this returns the actual temperature (not needed to pass the test)
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
//Draw Cells
canvas.selectAll('rect')
.data(data)
.enter()
.append('rect')
.attr('class', 'cell')
.attr('fill', (d) => {
variance = d['variance'];
if (variance <= -1) {
return 'SteelBlue';
} else if (variance <= 0) {
return 'LightSteelBlue';
} else if (variance <= 1) {
return 'Orange';
} else {
return 'Crimson';
}
})
.attr('data-month', (d) => {
return d.month - 1;
})
.attr('data-year', (d) => {
return d.year;
})
.attr('data-temp', (d) => {
return (baseTemp + d.variance);
})
10. Aligning cells with the corresponding year on the x-axis
In generateScales():
- Select the minimum and maximum year with d3.min and d3.max and assign them to variables
- Set the domain of the xScale to these. Add 1 to the max value since we are aligning the x with the left side
1
2
3
4
5
6
7
8
9
10
minYear = d3.min(data, (d) => {
return d.year;
});
maxYear = d3.max(data, (d) => {
return d.year;
});
xScale = d3.scaleLinear()
.domain([minYear, maxYear + 1])
.range([padding.width, canvasDimension.width - padding.width]);
In drawHeatMap():
- First, set the width attribute of the cells
- Select the minimum and maximum year with d3.min and d3.max and assign them to variables
- Create a variable to calculate the number of unique years by subtracting the lowest year from the highest year
- The area we have for the total width of all the blocks is the width minus padding for the left and right side
- So divide this by the number of years to distribute the width equally
- Second, set the x attribute
- Use the xScale giving the year attribute to return an x value in the correct range
1
2
3
4
5
.attr('x', (d) => {
return xScale(d.year)
.attr('width', (d) => {
return (canvasDimension.width - (2*padding.width)) / numberOfYears ;
})
In generateAxes():
- The alignment is tested with the axis ticks rather than the x coordinate so we need to fix the formatting
- Give it a tickformat and generate a new d3 format with ‘d’ which converts the years into decimal integers, removing the comma that was causing the tests to fail
1
2
let xAxis = d3.axisBottom(xScale)
.tickFormat(yearFormat);
11. Aligning cells with the corresponding month on the y-axis
In generateScales():
- Set the domain of yScale
- Since we are working with a scaleTime, we need to provide date objects as the domain
- Months will be on the y axis and we have a range of months, 0-11
- So create a date object with the month being zero and the month being 12 as the min and max domain.
- The reason the max is adjusted to 12 is to allow for a block for December which won’t show up otherwise
1
2
3
4
5
6
minMonth = new Date(0, 0, 0, 0, 0, 0, 0);
maxMonth = new Date(0, 12, 0, 0, 0, 0, 0);
yScale = d3.scaleTime()
.domain([minMonth, maxMonth])
.range([padding.height, canvasDimension.height - padding.height]);
In drawHeatMap():
- First, set the height attribute of our cells
- The area we have for the total height for all blocks is height minus top and bottom padding
- The cells are placed vertically based on the month, so divide by 12 to get equal heights for each cell
- Second, set the y coordinate of each cell
- Since we will use yScale to return a value in the correct range, give it a Date Object with the month set as the month of the item
- I have taken away 1 so that the height aligns with the tick which appears at the start (another adjustment that doesn’t quite make sense)
- The distance between the ticks should be the same as the height now
1
2
3
4
.attr('y', (d) => {
return yScale(new Date(0, (d.month - 1), 0, 0, 0, 0, 0, 0));
})
.attr('height', (canvasDimension.height - (2*padding.height)) / 12 )
12. Adding multiples tick labels on the y-axis with the full month name
In generateAxes():
- Give the yAxis a tickFormat
- Generate a d3 timeFormat which is used to display formatted dates for scaleTime
- %B means display the full month
1
2
let yAxis = d3.axisLeft(yScale)
.tickFormat(monthFormat);
13. Adding multiples tick labels on the x-axis with years between 1754 and 2015
In generateAxes():
- This was already completed when fulfilling user story 10
- All you need to do is remove the comma by setting the tickFormat for the xAxis:
1
2
let xAxis = d3.axisBottom(xScale)
.tickFormat(yearFormat);
14. Creating a legend with the corresponding id
- Create an svg element on the canvas with the id of ‘legend’
1
2
<svg id="legend">
</svg>
15. Adding some rectangle elements inside legend tag and filling them with a bunch of color to make map more readable
- Create some svg rectangles inside your ‘legend’ canvas like in the example below
- Give some text to specify the meaning of each color
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function drawLegend() {
let legend = d3.select('#legend')
.attr('width', legendDimension.width)
.attr('height', legendDimension.height);
legend.append('g')
.append('rect')
.attr('class', 'legendCell')
.attr('x', 10)
.attr('y', 0)
.attr('width', 40)
.attr('height', 40)
.attr('fill', 'SteelBlue');
legend.append('text')
.attr('x', 60)
.attr('y', 20)
.attr('fill', 'white')
.text('Variance of -1 or less')
.attr('class', 'legendText');
16. Creating a tooltip and adding some properties to it
- Create and select a div element in the document with the id of tooltip
1
2
3
4
5
let tooltip = d3.select('body')
.append('div')
.attr('id', 'tooltip')
.attr('class', 'tooltip')
.attr('data-year', d.year);
- Set the css of the tooltip div to visibility hidden, width and height auto
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
.tooltip {
border: solid 1px green;
position:absolute;
padding: .5rem;
text-align: center;
border-radius: .3rem;
font: 'Roboto', sans-serif;
box-shadow: 4px 4px 6px rgba(0, 0, 0, 0.4);
font-size: 14px;
opacity: 0;
background: #333;
align-items: centerx;
justify-items: center;
justify-content: center;
display: flex;
}
- Add a mouseover event to cells to make the tooltips visible
- Create an array with all the month names
- Set the text of the tooltip to display the fields from the array item, you can use the monthNames array to display the month as a string
- It doesn’t really matter what the tooltip text contains
- Add a mouseout event to the circles to make the tooltips hidden
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
.on('mouseover', (d, i) => {
tooltip.transition()
.duration(200)
.style('opacity', 0.9);
let months = [
'January',
'Febuary',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December'
]
tooltip.html("" + "Year: " + d.year + ' - ' + months[d.month - 1] + "<br/>" +
"Temperature: " + (baseTemp + d.variance) + " ℃" + "<br/>" +
"Variance: " + d.variance + " ℃" + "<br/>");
tooltip.style('left', (d3.event.pageX + 10) + 'px')
.style('top', (d3.event.pageY + 10) + 'px');
})
.on('mouseout', (d, i) => {
tooltip.transition()
.duration(200)
.style('opacity', 0);
})
16. Final touches and CSS styling
Source code
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Visualize data with a Heat Map</title>
<script src="https://d3js.org/d3.v5.min.js"></script>
<link rel="stylesheet" href="./style.css">
</head>
<body>
<h1 id="title" class="title">Monthly Global Land-Surface Temperature
<div id="description" class="title">1753 - 2015: Average temperature 8.66<strong>℃</strong></div>
</h1>
<svg id = 'canvas'>
</svg>
<svg id="legend">
</svg>
</body>
<script defer src="./script.js"></script>
</html>
style.css
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
@import url('https://fonts.googleapis.com/css?family=Roboto');
* {
font-family: 'Roboto', sans-serif;
}
html {
min-height: 100%;
}
body {
background-image: radial-gradient( circle 610px at 5.2% 51.6%, rgba(5,8,114,1) 0%, rgba(7,3,53,1) 97.5% );
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
/* height: 100%; */
font-family: 'Roboto', sans-serif;
min-height: 100%;
}
svg {
background-image: radial-gradient( circle 588px at 31.7% 40.2%, rgba(225,200,239,1) 21.4%, rgba(163,225,233,1) 57.1% );
/* background-color: whitesmoke; */
}
#canvas {
border: solid 1px cyan;
/* border-radius: 15px; */
min-height: 600;
min-width: 1200px;
border-radius: 8px;
}
.title {
text-align: center;
padding: 10px;
}
#title {
font-family: 'Roboto';
font-size: 36px;
font-weight: 700;
fill: white
}
#description {
color: #5AA364;
font-size: 24px;
font-family: 'Trebuchet MS', 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif;
}
.tooltip {
border: solid 1px green;
position:absolute;
padding: .5rem;
text-align: center;
border-radius: .3rem;
font: 'Roboto', sans-serif;
box-shadow: 4px 4px 6px rgba(0, 0, 0, 0.4);
font-size: 14px;
opacity: 0;
background: #333;
align-items: centerx;
justify-items: center;
justify-content: center;
display: flex;
}
.cell:hover {
fill: darkgreen;
}
.legendCell {
stroke: white;
}
.legendText {
font-size: 15px;
}
#legend {
border: solid 1px cyan;
padding: 10px;
margin: 10px;
}
script.js
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
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
// Declaration of variables
//Fetch data from the API
let url = 'https://raw.githubusercontent.com/freeCodeCamp/ProjectReferenceData/master/global-temperature.json';
let method = 'GET';
let xmlrequest = new XMLHttpRequest();
//Variables to store fetched data
let baseTemp;
let dataset;
let data = [];
//Create Scales
let xScale;
let yScale;
//Time format
let yearFormat = d3.format('d');
let monthFormat = d3.timeFormat('%B');
//Max and Min
let minYear;
let maxYear;
let minMonth;
let maxMonth;
//Create a tooltip
let tooltip = d3.select('body')
.append('div');
//Create a Canvas
let canvas = d3.select('#canvas')
//Canvas Dimensions
let canvasDimension = {
width: 1300,
height: 600
}
//Legend Dimensions
let legendDimension = {
width: 220,
height: 200
}
//Canvas padding
let padding = {
width: 120,
height: 80
}
//Drawing Canvas
function drawCanvas() {
canvas.attr('width', canvasDimension.width)
.attr('height', canvasDimension.height);
}
//Generating Scale
function generateScale(){
//Minimum and Maximum
minYear = d3.min(data, (d) => {
return d.year;
});
maxYear = d3.max(data, (d) => {
return d.year;
});
minMonth = new Date(0, 0, 0, 0, 0, 0, 0);
maxMonth = new Date(0, 12, 0, 0, 0, 0, 0);
//Scale for xAxis representating the years
xScale = d3.scaleLinear()
.domain([minYear, maxYear + 1])
.range([padding.width, canvasDimension.width - padding.width]);
//Scale for the yAxis representating the months
yScale = d3.scaleTime()
.domain([minMonth, maxMonth])
.range([padding.height, canvasDimension.height - padding.height]);
}
//Generate Axis with tick
function generateAxis() {
//Initialise Axis
let xAxis = d3.axisBottom(xScale)
.tickFormat(yearFormat);
let yAxis = d3.axisLeft(yScale)
.tickFormat(monthFormat);
//Render Axis
//xAxis
canvas.append('g')
.attr('id', 'x-axis')
.call(xAxis)
.attr('transform', 'translate(0, ' + (canvasDimension.height - padding.height ) + ')');
//yAxis
canvas.append('g')
.attr('id', 'y-axis')
.call(yAxis)
.attr('transform', 'translate(' + (padding.width) + ', 0)');
}
function drawHeatMap() {
let numberOfYears = maxYear - minYear;
//Draw Cells
canvas.selectAll('rect')
.data(data)
.enter()
.append('rect')
.attr('class', 'cell')
.attr('fill', (d) => {
variance = d['variance'];
if (variance <= -1) {
return 'SteelBlue';
} else if (variance <= 0) {
return 'LightSteelBlue';
} else if (variance <= 1) {
return 'Orange';
} else {
return 'Crimson';
}
})
.attr('data-month', (d) => {
return d.month - 1;
})
.attr('data-year', (d) => {
return d.year;
})
.attr('data-temp', (d) => {
return (baseTemp + d.variance);
})
.attr('x', (d) => {
return xScale(d.year)
})
.attr('y', (d) => {
return yScale(new Date(0, (d.month - 1), 0, 0, 0, 0, 0, 0));
})
.attr('height', (canvasDimension.height - (2*padding.height)) / 12 )
.attr('width', (d) => {
return (canvasDimension.width - (2*padding.width)) / numberOfYears ;
})
.on('mouseover', (d, i) => {
tooltip.attr('id', 'tooltip')
.attr('class', 'tooltip')
.attr('data-year', d.year);
tooltip.transition()
.duration(200)
.style('opacity', 0.9);
let months = [
'January',
'Febuary',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December'
]
tooltip.html("" + "Year: " + d.year + ' - ' + months[d.month - 1] + "<br/>" +
"Temperature: " + (baseTemp + d.variance) + " ℃" + "<br/>" +
"Variance: " + d.variance + " ℃" + "<br/>");
tooltip.style('left', (d3.event.pageX + 10) + 'px')
.style('top', (d3.event.pageY + 10) + 'px');
})
.on('mouseout', (d, i) => {
tooltip.transition()
.duration(200)
.style('opacity', 0);
})
}
//Draw Legend
function drawLegend() {
let legend = d3.select('#legend')
.attr('width', legendDimension.width)
.attr('height', legendDimension.height);
legend.append('g')
.append('rect')
.attr('class', 'legendCell')
.attr('x', 10)
.attr('y', 0)
.attr('width', 40)
.attr('height', 40)
.attr('fill', 'SteelBlue');
legend.append('text')
.attr('x', 60)
.attr('y', 20)
.attr('fill', 'white')
.text('Variance of -1 or less')
.attr('class', 'legendText');
legend.append('g')
.append('rect')
.attr('class', 'legendCell')
.attr('x', 10)
.attr('y', 40)
.attr('width', 40)
.attr('height', 40)
.attr('fill', 'LightSteelBlue');
legend.append('text')
.attr('x', 60)
.attr('y', 60)
.attr('fill', 'white')
.text('On or below Average')
.attr('class', 'legendText');
legend.append('g')
.append('rect')
.attr('class', 'legendCell')
.attr('x', 10)
.attr('y', 80)
.attr('width', 40)
.attr('height', 40)
.attr('fill', 'Orange');
legend.append('text')
.attr('x', 60)
.attr('y', 100)
.attr('fill', 'white')
.text('Above Average')
.attr('class', 'legendText');
legend.append('g')
.append('rect')
.attr('class', 'legendCell')
.attr('x', 10)
.attr('y', 120)
.attr('width', 40)
.attr('height', 40)
.attr('fill', 'Crimson')
legend.append('text')
.attr('x', 60)
.attr('y', 140)
.attr('fill', 'white')
.text('Variance of +1 or more')
.attr('class', 'legendText');
}
function drawHint() {
let monthHint = d3.select('#canvas')
.append('text')
.attr('class', 'info')
.attr('x', -300)
.attr('y', 40)
.attr('transform', 'rotate(-90)')
.text('Months')
.style('fill', 'white');
let owner = d3.select('#canvas')
.append('text')
.attr('class', 'info')
.attr('font-size', 14)
.attr('x', 1135)
.attr('y', 590)
.text('Made by Venom Cocytus')
.style('fill', 'white');
let yearHint = d3.select('#canvas')
.append('text')
.attr('class', 'info')
.attr('x', 620)
.attr('y', 565)
.text('Years')
.style('fill', 'white');
let legendInfo = d3.select('#legend')
.append('text')
.attr('class', 'info')
.attr('x', 90)
.attr('y', 190)
.text('Legend')
.style('fill', 'white');
}
//Main function
//Fetch Request
xmlrequest.open(method, url, true);
xmlrequest.onload = function(){
dataset = JSON.parse(xmlrequest.responseText);
data = dataset.monthlyVariance;
baseTemp = dataset.baseTemperature;
console.log(data);
console.log(baseTemp);
//Calling canvas function
drawCanvas();
generateScale();
generateAxis();
drawHeatMap();
drawLegend();
drawHint();
}
xmlrequest.send();
Interactive Frame
Links
Getting The Code On CodePen
The entire codePen containing all the code mentioned in this post can be found here.
Getting The Code On Github
The entire folder containing all the code mentioned in this post can be found on this link.
Just bear in mind that you will need to install all the dependencies. If you find any issues with the code, feel free to either comment down below or raise an issue on Github.
Add me on LinkedIn
Don’t hesitate to follow me on linkedIn or o other social network to encourage me to do more posts on IT.
Comments powered by Venom Cocytus.