A third attempt at panning and zooming with Orthographic projection. This version shows country boundaries, renders at a lower resolution while panning and zooming, and renders at a higher resolution after stopping.
Inspired by earth.nullschool.net and Versor Dragging.
forked from curran's block: Orthographic Zoom III
forked from curran's block: Orthographic Zoom III
xxxxxxxxxx
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://d3js.org/topojson.v1.min.js"></script>
</head>
<body>
<svg width="960" height="500"></svg>
<script>
const svg = d3.select('svg');
const path = svg.append('path').attr('stroke', 'gray');
const citiesG = svg.append('g');
const projection = d3.geoOrthographic();
const initialScale = projection.scale();
const geoPath = d3.geoPath().projection(projection);
let moving = false;
d3.queue()
.defer(d3.json, 'https://unpkg.com/world-atlas@1/world/110m.json')
.defer(d3.json, 'https://unpkg.com/world-atlas@1/world/50m.json')
.defer(d3.csv, 'geonames_cities100000.csv')
.await((error, world110m, world50m, cities) => {
const countries110m = topojson
.feature(world110m, world110m.objects.countries);
const countries50m = topojson
.feature(world50m, world50m.objects.countries);
const w = 960, h = 500;
const center = [w/2, h/2];
const render = () => {
path.attr('d', geoPath(moving ? countries110m : countries50m));
const circles = citiesG.selectAll('circle').data(cities);
circles.enter().append('circle')
.merge(circles)
.attr('cx', d => projection([d.longitude, d.latitude])[0])
.attr('cy', d => projection([d.longitude, d.latitude])[1])
.attr('fill', d => {
const coordinate = [d.longitude, d.latitude];
gdistance = d3.geoDistance(coordinate, projection.invert(center));
return gdistance > 1.57 ? 'none' : 'steelblue';
})
.attr('fill-opacity', 0.5)
.attr('r', 2);
};
render();
let rotate0, coords0;
const coords = () => projection.rotate(rotate0)
.invert([d3.event.x, d3.event.y]);
svg
.call(d3.drag()
.on('start', () => {
rotate0 = projection.rotate();
coords0 = coords();
moving = true;
})
.on('drag', () => {
const coords1 = coords();
projection.rotate([
rotate0[0] + coords1[0] - coords0[0],
rotate0[1] + coords1[1] - coords0[1],
])
render();
})
.on('end', () => {
moving = false;
render();
})
// Goal: let zoom handle pinch gestures (not working correctly).
.filter(() => !(d3.event.touches && d3.event.touches.length === 2))
)
.call(d3.zoom()
.on('zoom', () => {
projection.scale(initialScale * d3.event.transform.k);
render();
})
.on('start', () => {
moving = true;
})
.on('end', () => {
moving = false;
render();
})
)
});
</script>
</body>
https://d3js.org/d3.v4.min.js
https://d3js.org/topojson.v1.min.js