Notebooks 2.0 is here.

Published
Edited
Feb 7, 2022
6 stars
Insert cell
Insert cell
Insert cell
{
// USER DEFINED VARS
// set outer width and height for svg
const width = window.innerWidth * .9
const height = width * 2/3
// user defined: size of grid and # cells
const nrows = 10;
const ncols = 20;
// CHART STUFF
// chart constants
const margin = {
top: 70,
bottom: 50,
left: 60,
right: 50
}
// params for chart itself.
const gridWidth = width - margin.left - margin.right;
const gridHeight = height - margin.bottom - margin.top;
// make svg (use margin convention for spacing)
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})`)
// calculate cell size dynamically based on user input
const cellWidth = gridWidth / ncols;
const cellHeight = gridHeight / nrows;
// define scales to be dynamic based on grid size
const gridXScale = d3.scaleLinear().domain([0, ncols]).range([0, gridWidth]);
const gridYScale = d3.scaleLinear().domain([0, nrows]).range([0, gridHeight]);
// init grid data
let data = []
// loop thru and generate desired grid data
// let cell = 0;
for (let rowNumber = 0; rowNumber < nrows; rowNumber++) {
for (let colNumber = 0; colNumber < ncols; colNumber++) {
let obs = {
x: colNumber,
y: rowNumber,
height: cellHeight,
width: cellWidth
};
// add data to data
data.push(obs)
}
}
// DELAUNAY STUFF
const delan = d3.Delaunay.from(
data,
(d) => gridXScale(d.x),
(d) => gridYScale(d.y)
);

// create g tags to append to (in grid shape)
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)})`
})
// add the overlay on top of everything to take the mouse events
svgSel
.append("rect")
.attr("class", "overlay")
.attr("width", gridWidth + margin.left + margin.right)
.attr("height", gridHeight + margin.bottom + margin.top)
.style("opacity", 0)
// .style('pointer-events', 'none')
.on("mousemove", hover)
.on("mouseleave", unhover);

const circlePadding = 2
// append whatever in grid; circles here
sel.selectAll('g.grid').each(function(d,i) {
const cell = d3.select(this).append('g')
// append circles
cell.append('circle')
.attr('class', 'grid-circle')
.attr('r', cellWidth / 2 - circlePadding - 6)
.attr('fill', 'coral')
.attr('ii', i)
})
// .on('mouseover', function() {
// d3.select(this).attr("stroke", "purple").attr("stroke-width", 7)
// })
// .on('mouseout', function() {
// d3.select(this).attr("stroke", "purple").attr("stroke-width", 0)
// })
function hover(event) {
// get the current mouse position
const [mx, my] = d3.pointer(event);
// use the new diagram.find() function to find the Voronoi mouse position
// make sure to account for margin differences since delan on g
const closestPoint = delan.find(mx - margin.left, my - margin.top);
// highlight the point if we found one
const closestDataPoint = data[closestPoint];
// highlight current circle
d3.selectAll("circle.grid-circle").filter(
(d) => d.x === closestDataPoint.x && d.y === closestDataPoint.y
).attr("stroke", "purple").attr("stroke-width", 7).raise();
// unhover all other circles
d3.selectAll("circle.grid-circle").filter(
(d) => d.x !== closestDataPoint.x || d.y !== closestDataPoint.y
).attr('stroke-width', 0).attr('stroke', 'coral')
}
// unhover all cells
function unhover() {
d3.selectAll('circle.grid-circle').attr('stroke-width', 0).attr('stroke', 'coral')
}

return svg
}
Insert cell
Type JavaScript, then Shift-Enter. Ctrl-space for more options. Arrow ↑/↓ to switch modes.

Insert cell
Type JavaScript, then Shift-Enter. Ctrl-space for more options. Arrow ↑/↓ to switch modes.

Insert cell
d3 = require("d3@6", "d3-delaunay@5")
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more