projection.rotate([lambda, phi]) spins the sphere before projecting, so a globe is an orthographic projection whose rotation follows d3-drag. A script sets the frame with one drag:
<script src="https://cdn.jsdelivr.net/npm/d3@7.9.0/dist/d3.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/topojson-client@3.1.0"></script>
<svg width="720" height="210"></svg>
<script type="module">
const url = 'https://cdn.jsdelivr.net/npm/world-atlas@2.0.2/countries-110m.json';
const topo = await d3.json(url), svg = d3.select('svg');
const projection = d3.geoOrthographic().fitExtent([[255, 0], [465, 210]], { type: 'Sphere' })
.rotate([30, -20]); // over the Atlantic
const path = d3.geoPath(projection);
const layers = [[{ type: 'Sphere' }, '#e3f2fd'], [d3.geoGraticule10(), 'none', '#b0bec5'],
[topojson.feature(topo, topo.objects.countries), '#3f7d3a', 'white']]
.map(([d, fill, stroke]) => svg.append('path').datum(d).attr('fill', fill)
.attr('stroke', stroke));
const render = () => layers.forEach(layer => layer.attr('d', path));
const clamp = phi => Math.max(-90, Math.min(90, phi)); // keep the poles upright
svg.call(d3.drag().on('drag', event => {
const [lambda, phi] = projection.rotate(), k = 75 / projection.scale(); // degrees per px
projection.rotate([lambda + event.dx * k, clamp(phi - event.dy * k)]);
render();
}));
render();
const box = svg.node().getBoundingClientRect(), at = (x, y) => ({ view: window,
clientX: box.x + x, clientY: box.y + y }); // simulate one drag
svg.node().dispatchEvent(new MouseEvent('mousedown', at(360, 120)));
window.dispatchEvent(new MouseEvent('mousemove', at(170, 100)));
window.__done = true;
</script>
Dragging 190 px left and 20 px up turned the rotation from [30, -20] to [-105.7, -5.7] (logged in a test run), bringing India and Australia into view. For finer data, redraw a simplified layer while dragging, or draw with d3.geoPath(projection, context) (Canvas Rendering).