{
const width = window.innerWidth * .9
const height = width * 2/3
const nrows = 10;
const ncols = 20;
const margin = {
top: 70,
bottom: 50,
left: 60,
right: 50
}
const gridWidth = width - margin.left - margin.right;
const gridHeight = height - margin.bottom - margin.top;
const svg = DOM.svg(
gridWidth + margin.left + margin.right,
gridHeight + margin.bottom + margin.top
)
const svgSel = d3.select(svg)
const sel = svgSel.append('g')
.attr('transform', `translate(${margin.left},${margin.top})`)
const cellWidth = gridWidth / ncols;
const cellHeight = gridHeight / nrows;
const gridXScale = d3.scaleLinear().domain([0, ncols]).range([0, gridWidth]);
const gridYScale = d3.scaleLinear().domain([0, nrows]).range([0, gridHeight]);
let data = []
for (let rowNumber = 0; rowNumber < nrows; rowNumber++) {
for (let colNumber = 0; colNumber < ncols; colNumber++) {
let obs = {
x: colNumber,
y: rowNumber,
height: cellHeight,
width: cellWidth
};
data.push(obs)
}
}
const delan = d3.Delaunay.from(
data,
(d) => gridXScale(d.x),
(d) => gridYScale(d.y)
);
const join = sel.selectAll('g.grid')
.data(data)
.enter().append('g')
.attr('class', 'grid')
.attr('transform', (d, i) => {
return `translate(${gridXScale(d.x)}, ${gridYScale(d.y)})`
})
svgSel
.append("rect")
.attr("class", "overlay")
.attr("width", gridWidth + margin.left + margin.right)
.attr("height", gridHeight + margin.bottom + margin.top)
.style("opacity", 0)
.on("mousemove", hover)
.on("mouseleave", unhover);
const circlePadding = 2
sel.selectAll('g.grid').each(function(d,i) {
const cell = d3.select(this).append('g')
cell.append('circle')
.attr('class', 'grid-circle')
.attr('r', cellWidth / 2 - circlePadding - 6)
.attr('fill', 'coral')
.attr('ii', i)
})
function hover(event) {
const [mx, my] = d3.pointer(event);
const closestPoint = delan.find(mx - margin.left, my - margin.top);
const closestDataPoint = data[closestPoint];
d3.selectAll("circle.grid-circle").filter(
(d) => d.x === closestDataPoint.x && d.y === closestDataPoint.y
).attr("stroke", "purple").attr("stroke-width", 7).raise();
d3.selectAll("circle.grid-circle").filter(
(d) => d.x !== closestDataPoint.x || d.y !== closestDataPoint.y
).attr('stroke-width', 0).attr('stroke', 'coral')
}
function unhover() {
d3.selectAll('circle.grid-circle').attr('stroke-width', 0).attr('stroke', 'coral')
}
return svg
}