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
forked from earthjs'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>
<style>
canvas {
position: absolute;
z-index: 2;
top: 0;
left: 0;
}
</style>
</head>
<body>
<svg width="960" height="500"></svg>
<script>
const width = 960,
height = 500,
center = [width/2, height/2];
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);
const canvas = d3.select("body").append("canvas")
.attr("width", width)
.attr("height", height);
var context = canvas.node().getContext("2d");
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 render = () => {
path.attr('d', geoPath(moving ? countries110m : countries50m));
let dots1 = [];
const geoCircle = d3.geoCircle();
cities.forEach(function(d) {
const coordinate = [d.longitude, d.latitude];
const circle = geoCircle.center(coordinate).radius(2)();
if (d3.geoDistance(coordinate, center) > 1.57) {
dots1.push(circle);
}
});
context.beginPath();
geoPath({type: 'GeometryCollection', geometries: dots1});
context.lineWidth = 0.2;
context.fillStyle = 'rgb(100,0,0)';
context.strokeStyle = 'rgb(100,0,0)';
context.fill();
context.stroke();
};
render();
let rotate0, coords0;
const coords = () => projection.rotate(rotate0)
.invert([d3.event.x, d3.event.y]);
canvas
.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