block by harrystevens 8c8d3a489aa1372e14b8084f94b32464

Scale Bars for D3 Maps

Full Screen

Scale bars help viewers understand the geographic extent of maps. Printed maps, even those produced over a century ago, seldom lack them, yet scale bars are commonly missing from modern maps published on the internet. d3-geo-scale-bar makes it easy to add scale bars to maps created with d3-geo, a popular open source library for publishing maps on the web.

index.html

<!DOCTYPE html>
<html>
<head>
  <style>
    body {
      margin: 0;
    }
    svg {
      margin: 0 auto;
      display: table;
    }
    path {
      fill: #eee;
      stroke: #ddd;
    }
  </style>
</head>
<body>
  <script src="https://d3js.org/d3-dispatch.v1.min.js"></script>
  <script src="https://d3js.org/d3-selection.v1.min.js"></script>
  <script src="https://d3js.org/d3-transition.v1.min.js"></script>
  <script src="https://d3js.org/d3-zoom.v1.min.js"></script>
  <script src="https://d3js.org/d3-drag.v1.min.js"></script>
  <script src="https://d3js.org/d3-array.v1.min.js"></script>
  <script src="https://d3js.org/d3-geo.v1.min.js"></script>

  <script src="india.js"></script>  
  <script src="https://unpkg.com/d3-geo-scale-bar@1"></script>
  <script>
    let width, height;
    const svg = d3.select("body").append("svg");
    const g = svg.append("g");
    const polygon = g.append("path").datum(india);
    const projection = d3.geoMercator();
    const path = d3.geoPath().projection(projection);
    
    const miles = d3.geoScaleBar()
        .units(d3.geoScaleMiles)
        .top(.1)
        .left(.5)
        .distance(500);

    const scaleBarMiles = svg.append("g");

    const kilometers = d3.geoScaleBar()
        .left(.5)
        .top(.1)
        .distance(800);

    const scaleBarKilometers = svg.append("g")
        .attr("transform", "translate(0, 40)")
        .append("g");

    redraw();
    window.onresize = _ => redraw();

    function redraw(){
      width = window.innerWidth;
      height = Math.min(width * 1.12, window.innerHeight);

      svg.attr("width", width).attr("height", height);

      projection.fitSize([width, height], india);
      polygon.attr("d", path);
      miles.size([width, height]).projection(projection);
      scaleBarMiles.call(miles);
      kilometers.size([width, height]).projection(projection);
      scaleBarKilometers.call(kilometers);
    }
  </script>
</body>
</html>