{
const width = 960;
const height = 500;
const svg = d3.create("svg");
svg.attr("width", width).attr("height", height);
const projection = d3
.geoOrthographic()
.scale(250)
.translate([width / 2, height / 2])
.clipAngle(90);
const path = d3.geoPath().projection(projection);
svg
.append("path")
.datum({ type: "Sphere" })
.attr("class", "sphere")
.attr("d", path);
const graticule = d3.geoGraticule();
svg
.append("path")
.datum(graticule())
.attr("class", "graticule")
.attr("d", path)
.attr("fill", "none")
.attr("stroke", "#ccc");
const url =
"https://cdn.jsdelivr.net/npm/visionscarto-world-atlas@0.1.0/world/110m.json";
d3.json(url).then((world) => {
const countries = topojson.feature(world, world.objects.countries);
svg
.selectAll(".country")
.data(countries.features)
.enter()
.append("path")
.attr("class", "country")
.attr("d", path)
.attr("fill", "#69b3a2");
});
function rotateGlobe() {
d3.timer(function (elapsed) {
projection.rotate([elapsed / 200, -15]);
svg.selectAll("path").attr("d", path);
});
}
let rotation = [0, -20],
velocity = [0, 0],
lastTime = Date.now();
const sensitivity = 0.2,
deceleration = 0.95;
function dragstarted() {
velocity = [0, 0];
}
function dragged(event) {
const now = Date.now();
const time = now - lastTime;
lastTime = now;
const dx = event.dx * sensitivity;
const dy = event.dy * sensitivity;
rotation[0] += dx;
rotation[1] -= dy;
rotation[1] = Math.max(-90, Math.min(90, rotation[1]));
velocity = [dx / time, dy / time];
projection.rotate(rotation);
svg.selectAll("path").attr("d", path);
}
function dragended() {
const now = Date.now();
applyInertia(now);
}
function applyInertia(now) {
const delta = now - lastTime;
rotation[0] += velocity[0] * delta;
rotation[1] -= velocity[1] * delta;
velocity[0] *= deceleration;
velocity[1] *= deceleration;
projection.rotate(rotation);
svg.selectAll("path").attr("d", path);
if (Math.abs(velocity[0]) > 0.01 || Math.abs(velocity[1]) > 0.01) {
requestAnimationFrame(() => applyInertia(Date.now()));
}
}
svg.call(
d3.drag().on("start", dragstarted).on("drag", dragged).on("end", dragended)
);
return svg.node();
}