D3 v4/5 version of mbostock's Map Pan & Zoom.
Demonstrates map panning and zooming using SVG transforms to avoid the overhead of reprojecting at every zoom iteration.
D3 v4/5 version of mbostock's Map Pan & Zoom.
Demonstrates map panning and zooming using SVG transforms to avoid the overhead of reprojecting at every zoom iteration.
| <head> | |
| <style> | |
| body { | |
| margin: 0 | |
| } | |
| svg { | |
| background: #eee; | |
| } | |
| .sphere { | |
| fill: #fff; | |
| } | |
| .land { | |
| fill: #000; | |
| } | |
| .boundary { | |
| fill: none; | |
| stroke: #fff; | |
| stroke-linejoin: round; | |
| stroke-linecap: round; | |
| vector-effect: non-scaling-stroke; | |
| } | |
| </style> | |
| <script src="//d3js.org/d3.v5.min.js"></script> | |
| <script src="//unpkg.com/topojson@3"></script> | |
| </head> | |
| <body> | |
| <script> | |
| const width = window.innerWidth; | |
| const height = window.innerHeight; | |
| const projection = d3.geoMercator() | |
| .translate([width / 2, height / 2]) | |
| .scale((width - 1) / 2 / Math.PI); | |
| const path = d3.geoPath() | |
| .projection(projection); | |
| const zoom = d3.zoom() | |
| .scaleExtent([1, 8]) | |
| .on('zoom', zoomed); | |
| const svg = d3.select('body').append('svg') | |
| .attr('width', width) | |
| .attr('height', height); | |
| const g = svg.append('g'); | |
| svg.call(zoom); | |
| d3.json('//unpkg.com/world-atlas@1/world/110m.json') | |
| .then(world => { | |
| g.append('path') | |
| .datum({ type: 'Sphere' }) | |
| .attr('class', 'sphere') | |
| .attr('d', path); | |
| g.append('path') | |
| .datum(topojson.merge(world, world.objects.countries.geometries)) | |
| .attr('class', 'land') | |
| .attr('d', path); | |
| g.append('path') | |
| .datum(topojson.mesh(world, world.objects.countries, (a, b) => a !== b)) | |
| .attr('class', 'boundary') | |
| .attr('d', path); | |
| }); | |
| function zoomed() { | |
| g | |
| .selectAll('path') // To prevent stroke width from scaling | |
| .attr('transform', d3.event.transform); | |
| } | |
| </script> |