chart1 = {
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, chartHeight+150]);
const g = svg.append('g')
.attr('transform', `translate(${chartMargin.left}, ${chartMargin.top})`);
x.domain(d3.extent(covid_totals, d => d[xAxisParameter])).nice().range([0, width])
y.domain(d3.extent(covid_totals, d => d[yAxisParameter])).nice().range([chartHeight, 0])
const xAxis = d3.axisBottom(x).ticks(chartWidth / 100)
const xAxisGroup = g.append("g")
.attr("transform", `translate(0, ${chartHeight})`)
.call(xAxis)
.call(g => g.selectAll(".domain"));
xAxisGroup.append("text")
.attr("x", (width / 2))
.attr("y", chartMargin.bottom)
.attr("fill", "currentColor")
.attr("text-anchor", "middle")
.attr("font-size", "14px")
.text("Number of " + xAxisParameter);
const yAxis = d3.axisLeft(y).ticks(chartHeight / 100);
const yAxisGroup = g.append("g")
.call(yAxis)
.call(g => g.selectAll(".domain"));
yAxisGroup.append("text")
.attr("x", - chartMargin.left)
.attr("y", chartMargin.top - 25)
.attr("fill", "currentColor")
.attr("text-anchor", "middle")
.attr("font-size", "14px")
.classed("rotation", true)
.attr("transform", "translate(-40,200) rotate(-90)")
.text("Number of " + yAxisParameter);
// End of step 2
// Start of step 3
// 3.1 Add rectanle element
const grid = g.append("g");
grid.append("rect")
.attr("width", chartWidth)
.attr("height", chartHeight)
.attr("fill", "white");
let yLines = grid.append("g")
.selectAll("line");
let xLines = grid.append("g")
.selectAll("line");
// 3.2 Function to draw grid lines
function drawGridLines(x, y) {
yLines = yLines.data(y.ticks())
.join("line")
.attr("stroke", "#d3d3d3")
.attr("x1", 0)
.attr("x2", chartWidth - 80)
.attr("y1", d => 0.5 + y(d))
.attr("y2", d => 0.5 + y(d));
xLines = xLines.data(x.ticks())
.join("line")
.attr("stroke", "#d3d3d3")
.attr("x1", d => 0.5 + x(d))
.attr("x2", d => 0.5 + x(d))
.attr("y1", d => 0)
.attr("y2", d => chartHeight);
}
// 3.3 Draw grid lines
drawGridLines(x, y);
// End of step 3
// Start of step 4
// 4.1 Clip Path
const dotsGroup = g.append("g")
.attr("clip-path", "url(#border)");
svg.append("clipPath")
.attr("id", "border")
.append("rect")
.attr("width", width)
.attr("height", chartHeight);
// 4.2 Draw the circles
const radius = 5;
const dots = dotsGroup.selectAll("circle")
.data(covid_totals)
.join("circle")
.attr("cx", d => x(d[xAxisParameter]))
.attr("cy", d => y(d[yAxisParameter]))
.attr("fill", "steelblue")
.attr("r", radius)
// Next lines not included in step 4, Refer step 5
// 5.4 Attach mouse events
.on("mouseenter", mouseEnter)
.on("mouseleave", mouseLeave);
// End of step 4
// Start step 5
// 5.1 create tooltip
const tooltip = g.append("g")
.attr("visibility", "hidden");
const tooltipHeight = 25;
const tooltipRect = tooltip.append("rect")
.attr("fill", "black")
.attr("rx", 5)
.attr("height", tooltipHeight);
const tooltipText = tooltip.append("text")
.attr("fill", "white")
.attr("font-size", 14)
.attr("dy", 2)
.attr("dx", 2)
.attr("dominant-baseline", "hanging")
// 5.2 Mouse hover
function mouseEnter(event, d) {
// Make dot enlarge
d3.select(this)
.attr("r", radius * 2);
// Add text to tooltip
tooltipText.text(d.locality + " - " + xAxisParameter+ ": " + d[xAxisParameter] +
" , "+ yAxisParameter+ ": " + d[yAxisParameter]);
const labelWidth = tooltipText.node().getComputedTextLength();
// Set the width of the tooltip rectangle
tooltipRect.attr("width", labelWidth + 4);
// Move tooltip and set visible
const xPos = x(d[xAxisParameter]) + radius * 3;
const yPos = y(d[yAxisParameter]) - tooltipHeight / 2;
tooltip.attr("transform", `translate(${xPos},${yPos})`)
.attr("visibility", "visible");
}
// 5.3 Mouse leave
function mouseLeave(event, d) {
// Reset size
d3.select(this).attr("r", radius)
// Set invisible
tooltip.attr("visibility", "hidden");
}
// End step 5
// Start step 6
// 6.1 Set zoom settings
const zoom = d3.zoom()
.extent([[0, 0], [width-80, chartHeight-110]])
.scaleExtent([1, Infinity])
.on("zoom", onZoom);
g.call(zoom);
// 6.2 Create zoom callback
function onZoom(event) {
// Level of zoom
const xNew = event.transform.rescaleX(x);
const yNew = event.transform.rescaleY(y);
// Update dots
dots.attr("cx", d => xNew(d[xAxisParameter]))
.attr("cy", d => yNew(d[yAxisParameter]));
// Update axes
xAxisGroup.call(xAxis.scale(xNew))
.call(g => g.selectAll(".domain"));
yAxisGroup.call(yAxis.scale(yNew))
.call(g => g.selectAll(".domain"));
// Update grid
drawGridLines(xNew, yNew);
}
// End step 6
return svg.node();
}