scatter1 = {
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height+180])
.attr("width", width-50); ;
const g = svg.append('g')
.attr('transform', `translate(${margin.left}, ${margin.top})`);
x.domain(d3.extent(covid_totals, d => d[xaxis_value])).nice()
y.domain(d3.extent(covid_totals, d => d[yaxis_value])).nice()
const xAxis = d3.axisBottom(x);
const xAxisGroup = g.append("g")
.attr('transform', `translate(0, ${height})`)
.call(xAxis)
.call(g => g.selectAll('.domain'));
xAxisGroup.append('text')
.attr("x", (myWidth/2))
.attr("y", margin.bottom)
.attr("fill", "currentColor")
.attr("text-anchor", "middle")
.attr("font-size", "small")
.text(xaxis_value);
const yAxis = d3.axisLeft(y);
const yAxisGroup = g.append('g')
.call(yAxis)
.call(g => g.selectAll('.domain'));
yAxisGroup.append('text')
.attr("x", -margin.left)
.attr("y", margin.top-25)
.attr("fill", "currentColor")
.attr("text-anchor", "start")
.attr("font-size", "small")
.text(yaxis_value);
// https://observablehq.com/@weiglemc/interaction-in-d3?collection=@weiglemc/cs-725-825-spring-2021
// draw grid, based on https://observablehq.com/@nyuvis/interaction?collection=@nyuvis/guides-and-examples
const grid = g.append('g');
grid.append('rect')
.attr('width', width)
.attr("x", (margin.left-50))
.attr('height', height-50)
.attr('fill', 'white');
let yLines = grid.append('g')
.selectAll('line');
let xLines = grid.append('g')
.selectAll('line');
function drawGridLines(x, y) {
yLines = yLines.data(y.ticks())
.join('line')
.attr('stroke', '#d3d3d3')
.attr('x1', 0)
.attr('x2', width)
.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 => margin.top)
.attr('y2', d => height+10);
}
drawGridLines(x, y);
// https://observablehq.com/@weiglemc/interaction-in-d3?collection=@weiglemc/cs-725-825-spring-2021
// clip path hides dots that go outside when zooming
svg.append('clipPath')
.attr('id', 'border')
.append('rect')
.attr('width', width-80)
.attr('y', margin.top+10)
.attr('height', height-71)
.attr('fill', 'black');
const circlesGroup = g.append('g')
.attr('clip-path', 'url(#border)');
const radius = 5;
// draw the circles
const circles = circlesGroup.selectAll('circle')
.data(covid_totals)
.join("circle")
.attr("cx", d => x(d[xaxis_value]))
.attr("cy", d => y(d[yaxis_value]))
.attr("stroke", "black")
.attr('fill', 'steelblue') // Set the fill
.attr("r", radius)
// ********** new stuff starts here **********
.on('mouseenter', mouseEnter)
.on('mouseleave', mouseLeave);
// pan and zoom -https://observablehq.com/@nyuvis/interaction?collection=@nyuvis/guides-and-examples
const zoom = d3.zoom()
.extent([[0, 0], [width-80, height-110]])
// determine how much you can zoom out and in
.scaleExtent([1, Infinity])
.on('zoom', onZoom);
g.call(zoom);
function onZoom(event) {
// get updated scales
const xNew = event.transform.rescaleX(x);
const yNew = event.transform.rescaleY(y);
// update the position of the dots
circles.attr('cx', d => xNew(d[xaxis_value]))
.attr('cy', d => yNew(d[yaxis_value]));
// update the axes
xAxisGroup.call(xAxis.scale(xNew))
.call(g => g.selectAll('.domain'));
yAxisGroup.call(yAxis.scale(yNew))
.call(g => g.selectAll('.domain'));
// update the grid with new scales
drawGridLines(xNew, yNew);
}
// Hovering - https://observablehq.com/@nyuvis/interaction?collection=@nyuvis/guides-and-examples
// create tooltip
const tooltip = g.append('g')
.attr('visibility', 'hidden');
const tooltipHeight = 25;
const tooltipRect = tooltip.append('rect')
.attr('fill', 'grey')
.attr('rx', 5)
.attr('height', tooltipHeight);
const tooltipText = tooltip.append('text')
.attr('fill', 'white')
.attr('font-family', 'sans-serif')
.attr('font-size', 12)
.attr('dy', 2)
.attr('dx', 2)
.attr('dominant-baseline', 'hanging')
// handle hovering over a circle
function mouseEnter(event, d) {
// make the circle larger
d3.select(this)
.attr('r', radius * 2);
// update the text and get its width
tooltipText.text(d.locality + " - " + xaxis_value+ ": " + d[xaxis_value] + " , "+ yaxis_value+ ": " + d[yaxis_value]);
const labelWidth = tooltipText.node().getComputedTextLength();
// set the width of the tooltip's background rectangle
// to match the width of the label
tooltipRect.attr('width', labelWidth + 4);
// move the tooltip and make it visible
const xPos = x(d[xaxis_value]) + radius * 3;
const yPos = y(d[yaxis_value]) - tooltipHeight / 2;
tooltip.attr('transform', `translate(${xPos},${yPos})`)
.attr('visibility', 'visible');
}
// handle leaving a circle
function mouseLeave(event, d) {
// reset its size
d3.select(this)
.attr('r', radius)
// make the tooltip invisible
tooltip
.attr('visibility', 'hidden');
}
return svg.node();
}