Example of how to use the d3-hexgrid plugin with Canvas.
More examples... Farmers Markets I: SVG • Farmers Markets II: SVG and interaction • Military disputes: SVG with clipping • Post boxes: Canvas • all examples on Observable
| license: mit | |
| height: 500 | |
| border: no |
| .DS_Store |
Example of how to use the d3-hexgrid plugin with Canvas.
More examples... Farmers Markets I: SVG • Farmers Markets II: SVG and interaction • Military disputes: SVG with clipping • Post boxes: Canvas • all examples on Observable
| function ready(geo, userData) { | |
| // Some set up. | |
| const width = 900; | |
| const height = 500; | |
| const pr = window.devicePixelRatio || 1; | |
| // Crisp canvas and context. | |
| const canvas = d3.select('canvas') | |
| .attr('width', width * pr) | |
| .attr('height', height * pr) | |
| .style('width', `${width}px`); | |
| const context = canvas.node().getContext('2d'); | |
| context.scale(pr, pr); | |
| // Background. | |
| const gradient = context.createRadialGradient(width / 2, height / 2, 5, width / 2, height / 2, width / 2); | |
| gradient.addColorStop(0, '#0C2648'); | |
| gradient.addColorStop(1, '#091426'); | |
| context.fillStyle = gradient; | |
| context.fillRect(0, 0, width, height); | |
| // Projection and path. | |
| const projection = d3.geoRobinson().fitSize([width, height], geo); | |
| const geoPath = d3.geoPath() | |
| .projection(projection) | |
| .context(context); | |
| // Prep user data. | |
| userData.forEach(site => { | |
| const coords = projection([+site.lng, +site.lat]); | |
| site.x = coords[0]; | |
| site.y = coords[1]; | |
| }); | |
| // Hexgrid generator. | |
| const hexgrid = d3.hexgrid() | |
| .extent([width, height]) | |
| .geography(geo) | |
| .projection(projection) | |
| .pathGenerator(geoPath) | |
| .hexRadius(2); | |
| // Hexgrid instanace. | |
| const hex = hexgrid(userData); | |
| // Colour scale. | |
| const counts = hex.grid.layout | |
| .map(el => el.datapointsWt) | |
| .filter(el => el > 0); | |
| const ckBreaks = ss.ckmeans(counts, 4).map(clusters => clusters[0]); | |
| const colour = d3 | |
| .scaleThreshold() | |
| .domain(ckBreaks) | |
| .range(['#293e5a', '#5e6d7c', '#929b9f', '#c7cac1', '#fbf8e3']); | |
| // Draw prep. | |
| const hexagon = new Path2D(hex.hexagon()); | |
| // Draw. | |
| hex.grid.layout.forEach(hex => { | |
| context.save(); | |
| context.translate(hex.x, hex.y); | |
| context.fillStyle = colour(hex.datapointsWt); | |
| context.fill(hexagon); | |
| context.restore(); | |
| }); | |
| } | |
| // Load data. | |
| const world = d3.json( | |
| 'https://raw.githubusercontent.com/larsvers/map-store/master/earth-lands-10km.json' | |
| ); | |
| const points = d3.csv( | |
| 'https://raw.githubusercontent.com/larsvers/data-store/master/cities_top_10000_world.csv' | |
| ); | |
| Promise.all([world, points]).then(res => { | |
| let [geoData, userData] = res; | |
| ready(geoData, userData); | |
| }); |
| <!doctype html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="utf-8"> | |
| <title>Cities</title> | |
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |
| <!-- d3-hexgrid script comes first. --> | |
| <script src="//unpkg.com/d3-hexgrid"></script> | |
| <script src="//unpkg.com/d3"></script> | |
| <script src="//unpkg.com/d3-geo-projection"></script> | |
| <script src='//unpkg.com/simple-statistics'></script> | |
| </head> | |
| <body> | |
| <div id="container"> | |
| <canvas></canvas> | |
| </div> | |
| <script src="app.js"></script> | |
| </body> | |
| </html> |