block by pnavarrc 75ec1502f51f86c2f43e

Adding labels to a Map

Full Screen

index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1">

  <title>Adding Labels to the Map</title>

  <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js"></script>
</head>
<body>

  <style>
  body {
    margin: 0;
  }

  svg {
    background-color: #A7DBD8;
  }

  .sphere {
    fill: #A7DBD8;
    stroke: #79A09E;
  }

  .land {
    fill: #E0E4CC;
    stroke: #ACAF9F;
    stroke-width: 1;
  }

  .graticule {
    fill: none;
    stroke: #79A09E;
    stroke-width: 1;
    stroke-dasharray: 1,2;
  }

  .label {
    font-family: 'Helvetica Neue', Helvetica, sans-serif;
    font-size: 11px;
    fill: #777;
  }
  </style>

  <div id="map-container"></div>

  <script>

    // Set the dimensions of the map
    var width  = 960,
        height = 480;

    var state = {
      x: 0,
      y: 0,
      scale: height / 2
    };

    // Create a selection for the container div and append the svg element
    var div = d3.select('#map-container'),
        svg = div.append('svg');

    // Set the size of the SVG element
    svg.attr('width', width).attr('height', height);

    // Create and configure a geographic projection
    var projection = d3.geo.equirectangular()
      .translate([width / 2, height / 2]);

    // Create and configure a path generator
    var pathGenerator = d3.geo.path()
      .projection(projection);

    // Create and configure the graticule generator (one line every 20 degrees)
    var graticule = d3.geo.graticule();

    // Retrieve the geographic data asynchronously
    d3.json('countries.geojson', function(err, data) {

      // Throw errors on getting or parsing the file
      if (err) { throw err; }

      // Create a group to hold the map-related features
      var grp = svg.selectAll('g.container').data([data]);

      grp.enter().append('g').classed('container', true);
      grp.exit().remove();

      // Shpere (map boundaries)
      var sphere = grp.selectAll('path.sphere').data([{type: 'Sphere'}]);

      sphere.enter().append('path').classed('sphere', true);
      sphere.attr('d', pathGenerator);
      sphere.exit().remove();

      // Graticule lines (behind the land)
      var lines = grp.selectAll('path.graticule').data([graticule()]);

      lines.enter().append('path').classed('graticule', true);
      lines.attr('d', pathGenerator);
      lines.exit().remove();

      // Land
      var land = grp.selectAll('path.land').data([data]);

      land.enter().append('path').classed('land', true);
      land.attr('d', pathGenerator);
      land.exit().remove();

      // Filter down the labels by label rank (only show the most important labels)
      var labelData = data.features.filter(function(d) {
        return d.properties.labelrank < 4;
      });

      var labels = grp.selectAll('text.label').data(labelData);

      labels.enter().append('text')
        .classed('label', true);

      labels
        .attr('x', function(d) { return projection(d3.geo.centroid(d))[0]; })
        .attr('y', function(d) { return projection(d3.geo.centroid(d))[1]; })
        .attr('text-anchor', function(d, i) {
          // Randomly align the label
          var idx = Math.round(3 * Math.random());
          return ['start', 'middle', 'end'][idx];
        })
        .text(function(d) { return d.properties.admin; });

      labels.exit().remove();

    });
  </script>

</body>
</html>

Makefile

# Download and Transform the 1:50m Country Shapefiles from Natural Earth
# http://www.naturalearthdata.com/downloads/50m-cultural-vectors/

URL = http://www.naturalearthdata.com/http//www.naturalearthdata.com/download/50m/cultural/ne_50m_admin_0_countries.zip

# Download the zip file from the Natural Earth server
ne_50m_admin_0_countries.zip:
	curl -LO $(URL)

# Unzip the shapefiles
ne_50m_admin_0_countries.shp: ne_50m_admin_0_countries.zip
	unzip ne_50m_admin_0_countries.zip
	touch ne_50m_admin_0_countries.shp

# Convert the shapefiles to GeoJSON
countries.geojson: ne_50m_admin_0_countries.shp
	ogr2ogr -f GeoJSON countries.geojson ne_50m_admin_0_countries.shp

# Convert the GeoJSON file to TopoJSON
countries.topojson: countries.geojson
	topojson -p -o countries.topojson countries.geojson

# Remove source and temporary files
clean:
	rm ne_50m_admin_0_countries*