Search code examples
javascriptd3.jsmapsmercator

How to label cities in a Geographical Map using D3.js?


I am using D3.js to draw the geographical map of USA using Mercator projection. The map represents the population in each city across the USA. The population data is stored in the following file:

https://gist.githubusercontent.com/d3byex/65a128a9a499f7f0b37d/raw/176771c2f08dbd3431009ae27bef9b2f2fb56e36/us-cities.csv

Circles denoting the location of cities are displayed in the map.

The code is pasted below:

<!DOCTYPE html>
<html>
<head>
    <meta name="description" content="D3byEX 12.18" />
    <meta charset="utf-8">
</head>
<body>
    <script src="http://d3js.org/d3.v3.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/queue-async/1.0.7/queue.min.js"></script>
    <script>

        var width = 1000, height = 500;
        var svg = d3.select('body')
            .append('svg')
            .attr({
                width: width,
                height: height
            });

        var usDataUrl = 'https://gist.githubusercontent.com/d3byex/65a128a9a499f7f0b37d/raw/176771c2f08dbd3431009ae27bef9b2f2fb56e36/us-states.json',
            citiesDataUrl = 'https://gist.githubusercontent.com/d3byex/65a128a9a499f7f0b37d/raw/176771c2f08dbd3431009ae27bef9b2f2fb56e36/us-cities.csv';

        queue()
            .defer(d3.json, usDataUrl)
            .defer(d3.csv, citiesDataUrl)
            .await(function (error, states, cities) {
                var path = d3.geo.path();
                var projection = d3.geo.albersUsa()
                    .translate([width / 2, height / 2])
                    .scale([1000]);
                path.projection(projection);

                svg.selectAll('path')
                    .data(states.features)
                    .enter()
                    .append('path')
                    .attr('d', path)
                    .style({
                        fill: 'none',
                        stroke: 'black'
                    });

                svg.selectAll('circle')
                          .data(cities)
                          .enter()
                          .append('circle')
                          .each(function (d) {
                              var location = projection([d.longitude, d.latitude]);
                              d3.select(this).attr({
                                  cx: location[0], cy: location[1],
                                  r: Math.sqrt(+d.population * 0.00004)
                              });
                          })
                          .style({
                              fill: 'blue',
                              opacity: 0.75
                          });
            });
    </script>
</body>
</html>



But how to add labels of city names to those circles while hovering over them ?


Solution

  • The most basic (and ugly) method of creating a tooltip is using <title>:

    svg.selectAll('circle')
        .data(cities)
        .enter()
        .append('circle')
        .each(function (d) {
                var location = projection([d.longitude, d.latitude]);
                d3.select(this).attr({
                cx: location[0], cy: location[1],
                r: Math.sqrt(+d.population * 0.00004)
                });
         })
        .style({
               fill: 'blue',
               opacity: 0.75
         })
        .append("title")
        .text(d=>d.name);