← Examples
countries · orthographic · graticule · interactive

Globe

World countries rendered on an orthographic projection — the view from space. Land in sage green, ocean in slate blue, 30° graticule in white. Drag to rotate.

API Call

https://api.mapjson.com/v1/geo?layer=countries&detail=low

Code

<!DOCTYPE html>
<html>
<head>
  <script src="https://cdn.jsdelivr.net/npm/d3@7/dist/d3.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/topojson-client@3/dist/topojson-client.min.js"></script>
  <style>
    body { background: #1a2a3a; margin: 0; }
    svg { width: 100%; display: block; }
  </style>
</head>
<body>
  <div id="map"></div>
  <script>
    const width = 800, height = 800;
    const svg = d3.select("#map").append("svg").attr("viewBox", `0 0 ${width} ${height}`);

    const projection = d3.geoOrthographic()
      .scale(width / 2 - 20)
      .translate([width / 2, height / 2])
      .clipAngle(90)
      .rotate([0, -20]);

    const path = d3.geoPath().projection(projection);
    const graticule = d3.geoGraticule().step([30, 30])();

    // Ocean fill
    svg.append("circle")
      .attr("cx", width / 2).attr("cy", height / 2)
      .attr("r", projection.scale())
      .attr("fill", "#3a6a8a");

    // Graticule
    const graticulePath = svg.append("path")
      .datum(graticule)
      .attr("fill", "none")
      .attr("stroke", "white")
      .attr("stroke-width", 0.3)
      .attr("stroke-opacity", 0.3)
      .attr("d", path);

    // Countries (land)
    let landPath;

    const url = "https://api.mapjson.com/v1/geo?layer=countries&detail=low";

    d3.json(url).then(topo => {
      const countries = topojson.feature(topo, topo.objects.geo);

      landPath = svg.append("path")
        .datum(countries)
        .attr("fill", "#8a9e7a")
        .attr("stroke", "#3a6a8a")
        .attr("stroke-width", 0.4)
        .attr("d", path);
    });

    // Globe outline
    svg.append("circle")
      .attr("cx", width / 2).attr("cy", height / 2)
      .attr("r", projection.scale())
      .attr("fill", "none")
      .attr("stroke", "white")
      .attr("stroke-width", 0.5)
      .attr("stroke-opacity", 0.3);

    // Drag to rotate
    let lambda = 0, phi = -20;

    svg.call(d3.drag().on("drag", function(event) {
      lambda += event.dx * 0.4;
      phi = Math.max(-90, Math.min(90, phi - event.dy * 0.4));
      projection.rotate([lambda, phi]);
      graticulePath.attr("d", path);
      if (landPath) landPath.attr("d", path);
    })).style("cursor", "grab");
  </script>
</body>
</html>