Public
Edited
Jan 23, 2024
Insert cell
Insert cell
Insert cell
canvas = {
const map = usAlbersCountiesGeo
const height = 600

const fillDefault = '#cdb4db'
const fillSelected = '#231942'

const ctx = DOM.context2d(width, height)
// Set canvas dimensions
const scale = Math.max(2, window.devicePixelRatio)
ctx.canvas.style.width = `${width}px`
ctx.canvas.style.height = `${height}px`
ctx.canvas.width = width * scale
ctx.canvas.height = height * scale
ctx.scale(scale, scale)
// Projection
const projection = d3.geoAlbersUsa()
.translate([width/2, height/2])
// Paths-generating function
const path = d3.geoPath()
.projection(projection)

// Map data
const mapData = map.features.map((d, i) => ({
d: path(d),
p: new Path2D(path(d)),
centroid: path.centroid(d),
fill: fillDefault,
stroke: 'white'
}))

// Function to draw the map on canvas
const drawMap = (ctx) => {
for (const { p, fill, stroke } of mapData) {
ctx.fillStyle = fill
ctx.strokeStyle = stroke
ctx.stroke(p)
ctx.fill(p)
}
}
// Draw the map on canvas
drawMap(ctx)

// Listen for mouse moves - simulate a hover on shape
// On each mouse move, loop through all the 'shapes' and use isPointInPath to check for each of them
// if the mouse is inside. If it is, draw the shape with a new colour, else draw the shape with its original colour
ctx.canvas.addEventListener("mousemove", (event) => {
mapData.forEach(({ p, fill, stroke }) => {
const isPointInPath = ctx.isPointInPath(p, event.offsetX*scale, event.offsetY*scale)
ctx.fillStyle = isPointInPath ? fillSelected : fill
ctx.stroke(p)
ctx.fill(p)

// Note: this looks like a good idea as the shape is filled only if hovered
// but it's not, as the once hovered states will never go back to their original colour
// even when we've moved the mouse out - uncomment to see
// if (isPointInPath) {
// ctx.fillStyle = fillSelected
// ctx.stroke(p)
// ctx.fill(p)
// }
})
});
return ctx.canvas;
}
Insert cell
usAlbersCountiesGeo = topojson.feature(usAlbersCountiesTopo, "collection")
Insert cell
usAlbersCountiesTopo = FileAttachment("us-albers-counties.json").json()
Insert cell
topojson = require('topojson-client@3', 'topojson-simplify@3')
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