What is the best method to retrieve the country name from a world map using D3.js?

I'm trying to figure out how to retrieve the country name from a click event on the D3 world map. Despite inspecting the DOM, I can't quite understand how the country's name, code, or population is associated with the map.

The template for this project was taken from

// The svg
const svg = d3.select("svg"),
  width = +svg.attr("width"),
  height = +svg.attr("height");

// Map and projection
const path = d3.geoPath();
const projection = d3.geoMercator()
  .scale(70)
  .center([0, 20])
  .translate([width / 2, height / 2]);

// Data and color scale
let data = new Map()
const colorScale = d3.scaleThreshold()
  .domain([100000, 1000000, 10000000, 30000000, 100000000, 500000000])
  .range(d3.schemeBlues[7]);

// Load external data and boot
Promise.all([
  d3.json("https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/world.geojson"),
  d3.csv("https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/world_population.csv", function(d) {
    data.set(d.name, d.code, +d.pop)
  })
]).then(function(loadData) {
  let topo = loadData[0]
  let mouseClick = function(d) {
    d3.selectAll(".Country")
      .transition()
      .duration(200)
      .style("opacity", .8)
    d3.select(this)
      .transition()
      .duration(200)
      .style("stroke", "transparent")
    console.log(this.name)
  }
  // Draw the map
  svg.append("g")
    .selectAll("path")
    .data(topo.features)
    .join("path")
    // draw each country
    .attr("d", d3.geoPath()
      .projection(projection)
    )
    // set the color of each country
    .attr("fill", function(d) {
      d.total = data.get(d.id) || 0;
      return colorScale(d.total);
    })
})
<script src="https://d3js.org/d3.v6.js"></script>
<svg id="my_dataviz" width="400" height="300"></svg>

Answer №1

Make sure to update the mouseClick function in your JavaScript code.

Code:

<html>
      <script src="https://d3js.org/d3.v6.js"></script>
      <svg id="my_dataviz" width="400" height="300"></svg>
      <script>
        // The svg
        const svg = d3.select("svg"),
          width = +svg.attr("width"),
          height = +svg.attr("height");
    
        // Map and projection
        const path = d3.geoPath();
        const projection = d3
          .geoMercator()
          .scale(70)
          .center([0, 20])
          .translate([width / 2, height / 2]);
    
        // Data and color scale
        let data = new Map();
        const colorScale = d3
          .scaleThreshold()
          .domain([100000, 1000000, 10000000, 30000000, 100000000, 500000000])
          .range(d3.schemeBlues[7]);
    
        // Load external data and boot
        Promise.all([
          d3.json(
            "https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/world.geojson"
          ),
          d3.csv(
            "https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/world_population.csv",
            function (d) {
              data.set(d.name, d.code, +d.pop);
            }
          ),
        ]).then(function (loadData) {
          let topo = loadData[0];
    
          // Modify the mouseClick function here
          let mouseClick = function (event, d) {
            d3.selectAll(".Country")
              .transition()
              .duration(200)
              .style("opacity", 0.8);
            d3.select(this)
              .transition()
              .duration(200)
              .style("stroke", "transparent");
            console.log(d.properties.name); // Log the country name
          };
    
          // Draw the map
          svg
            .append("g")
            .selectAll("path")
            .data(topo.features)
            .join("path")
            // draw each country
            .attr("d", d3.geoPath().projection(projection))
            // set the color of each country
            .attr("fill", function (d) {
              d.total = data.get(d.id) || 0;
              return colorScale(d.total);
            })
            .on("click", mouseClick); // Attach the updated mouseClick function
        });
      </script>
    </html>

Hope this adjustment works for you.

Answer №2

Please remember to include this code snippet:

    .attr("country-name", d => d.properties.name)
          .on("click", function(){
           console.log(d3.select(this).attr("country-name"))
          })

        // Defining the svg
        const svg = d3.select("svg"),
          width = +svg.attr("width"),
          height = +svg.attr("height");
    
        // Map setup and projection
        const path = d3.geoPath();
        const projection = d3
          .geoMercator()
          .scale(70)
          .center([0, 20])
          .translate([width / 2, height / 2]);
    
        // Initializing data and color scale
        let data = new Map();
        const colorScale = d3
          .scaleThreshold()
          .domain([100000, 1000000, 10000000, 30000000, 100000000, 500000000])
          .range(d3.schemeBlues[7]);
    
        // Loading external data and commencement
        Promise.all([
          d3.json(
            "https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/world.geojson"
          ),
          d3.csv(
            "https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/world_population.csv",
            function (d) {
              data.set(d.name, d.code, +d.pop);
            }
          ),
        ]).then(function (loadData) {
          let topo = loadData[0];
    
          // Click function for mouse
          let mouseClick = function (event, d) {
            d3.selectAll(".Country")
              .transition()
              .duration(200)
              .style("opacity", 0.8);
            d3.select(this)
              .transition()
              .duration(200)
              .style("stroke", "transparent");
            console.log(d.properties.name); // Country name displayed in log
          };
    
          // Rendering the map
          svg
            .append("g")
            .selectAll("path")
            .data(topo.features)
            .join("path")
            // drawing each country shape
            .attr("d", d3.geoPath().projection(projection))
            // setting the color of each country based on population
            .attr("fill", function (d) {
              d.total = data.get(d.id) || 0;
              return colorScale(d.total);
            })
            .attr("country-name", d => d.properties.name)
          .on("click", function(){
           console.log(d3.select(this).attr("country-name"))
          })
            
        });
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.8.5/d3.min.js"></script>
 <svg id="my_dataviz" width="400" height="300"></svg>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Toggle the visibility of an element with a single button click

Below is a snippet of my sample code: SAMPLE HTML CODE: <ul> <li class="item"> item 1 </li> <li class="item"> item 1 </li> <li class="item"> item 1 </li> <li class="item"> item 1 </li> <l ...

The element type is not valid: it should be a string for built-in components or a class/function for composite components, but it is currently an object in a React project

In the process of developing a React app to explore MUI capabilities, I encountered an error in my browser: The issue reported is: Element type is invalid - expected a string (for built-in components) or a class/function (for composite components), but rec ...

When Safari injects elements that were previously hidden with display:none, they remain visible

Using the JS library MagnificPopup, I implement popups on my website triggered by a "read more" button. This library moves the html to display it in a different location and then injects it back when the popup is closed. While this functionality works seam ...

Unable to set a value for the variable

const readline = require('readline'); let favoriteFood; const rl = readline.createInterface(process.stdin, process.stdout); rl.question('What is your favorite food?', function(answer) { console.log('Oh, so your favorite food is &a ...

What advantages and disadvantages come with using timeouts versus using countdowns in conjunction with an asynchronous content loading call in JavaScript/jQuery?

It seems to me that I may be overcomplicating things with the recursive approach. Wait for 2 seconds before loading the first set of modules: function loadFirstSet() { $('[data-content]:not(.loaded)').each( function() { $(this).load($(thi ...

Partial view remains stagnant despite successful ajax post completion

I am currently in the process of developing a system that will showcase uploaded images from a file input into a specific div within my view. (with intentions to incorporate document support in the future) The challenge I am facing is that the partial vie ...

The Google Visualization chart fails to display properly once CSS is applied

Struggling with a graph display issue here. It's quite perplexing as it works fine on older laptops and Safari, but not on Chrome or older versions of Firefox. Works like a charm on my old laptop and Safari, but fails on Chrome and Firefox (haven&apo ...

How do I make a component in React delete itself from a page when its internal state changes?

For instance: {!loading ? (data.map((v, i) => { return <Card key={i} title={v.name} image={v.pictures.sizes[4].link}} /> }) These cards are displayed as a series of components on the main screen. Each card ...

Resolve the route expression before the API request is fully processed

As a hobby coder, I have some gaps in my knowledge and despite trying various solutions, I have not been able to solve this issue. Idea Outcome My goal is to call my Express server, retrieve data from an external API, and render the data once it's f ...

Issues with Grunt functionality after installation on Ubuntu

I successfully installed Grunt by running the following commands in the terminal: sudo apt-get install nodejs sudo apt-get install npm npm install -g grunt-cli After executing npm install -g grunt-cli, here is the output from the terminal: (output he ...

The data visualization tool Highchart is struggling to load

As I try to integrate highcharts into my website, I encounter an unexpected error stating TypeError: $(...).highcharts is not a function. Below is the code snippet in question: @scripts = {<script src="@routes.Assets.at("javascripts/tracknplan.js")" ty ...

streamlining form updates in vue

The code snippet provided is functional but unnecessarily complicated and lengthy. I am seeking a more efficient approach to achieve the desired outcome. <h6><label for="number">Change Number</label></h6> ...

Dealing with empty POST request bodies in Node.js Express is a common challenge

In my Node.JS project using Express framework, I am encountering an issue while trying to access the body of a POST request. The POST request is being sent through an HTML form, and upon checking with WireShark, I can see that the request is indeed getting ...

Adding an iframe with inline script to my Next.js website: A step-by-step guide

For my Next.js project, I have this iframe that needs to be integrated: <iframe class="plot" aria-label="Map" id="datawrapper-chart-${id}" src="https://datawrapper.dwcdn.net/${id}/1/" style="width: ...

"Drag and drop elements that automatically snap to a grid and move with

I'm trying to create a small, square div that follows the mouse cursor, but I want it to snap to a 3x3 pixel grid. Here is what I have so far: $(document).mousemove(function(e) { window.x = e.pageX; window.y = e.pageY; if(window.x % 9 === 0 ){ ...

Trying out the Send feature of Gmail API using Postman

Attempting to use the Gmail API for sending emails. Utilizing Postman as a tool to test requests and obtain correct code for web application integration, encountering an error: { "error": { "errors": [ { "domain": "global", ...

Tips for streamlining code using switch statements in vue.js

Is there a more efficient way to simplify this switch statement for handling 5 different cases? Can I streamline the process of updating the completion status based on each step? data() { return { stepOneIsCompleted: false, ...

Error message encountered when deploying a Discord bot on Heroku: "SyntaxError: Unexpected token '??='"

I encountered an issue when trying to deploy a Discord bot that I created using Node.js on Heroku. The error message is as follows: 2021-11-05T00:00:10.334347+00:00 app[web.1]: > node . 2021-11-05T00:00:10.334348+00:00 app[web.1]: 2021-11-05T00:00:10.3 ...

NPM: The registry cannot be found

npm http GET https://registry.npmjs.org/n npm ERR! Error: failed to fetch from registry: n npm ERR! at /usr/share/npm/lib/utils/npm-registry-client/get.js:139:12 npm ERR! at cb (/usr/share/npm/lib/utils/npm-registry-client/request.js:31:9) npm ERR ...

When the user clicks, show a designated search result in a separate container

I've been developing my Angular cocktail application, and I've reached a point where I can display all the cocktails in my database (only showing names). Now, I want to implement a feature where if I click on a specific cocktail, its full content ...