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

Adjust alterations in a Vue Component to apply to separate routes

I have a Filter tab component that I use in various routes. When I click on a tab, it becomes active. After clicking on one tab, I want it to remain active in other routes as well. How can I achieve this? Any suggestions or articles would be greatly apprec ...

What advantages can be gained from having multiple package.json files within a single application?

Embarking on the journey of creating my inaugural full react web application entirely from scratch. Previously, I've mainly worked on assignments that were partially pre-made for me. While setting up my project, I couldn't help but notice that I ...

Alter the Header/Navigation to switch colors depending on the section of the website currently being viewed

I'm currently revamping my personal portfolio website and had an idea for a cool feature. I want the header/navigation bar to change color based on which section of the webpage it's in (the site is one page only). My initial thought was to add o ...

What techniques can be used to optimize Angular template integration and minimize http requests?

Situation: Our team is currently in the process of migrating an ASP.NET application from traditional WebForms to Web API + Angular. The application is primarily used in regions with limited internet connectivity, where latency issues overshadow bandwidth c ...

Ensure that the initial section of the page spans the full height of the browser, while all subsequent sections have a

I have a website composed of various blocks with different heights, all extending to full width. My goal is to make the first block the full height and width of the browser window, while keeping the other blocks at a set height as seen on this site: After ...

Repetitive calling of a Node.js function

Currently, I am developing using the nodejs express framework. On my webpage, there are two buttons: 1) Submit, which triggers the following function: router.get('/record_enrich_quick/:quick', function(req, res) { console.trace(); var j ...

Rendering on the server with React, React-Router, and Express

I'm currently in the process of setting up server-side rendering for my react application and I'm utilizing the fantastic react-router module to enable it to manage non-js scenarios (such as certain crawlers or users with javascript disabled). Ne ...

Dealing with submit errors in React Redux forms

I am facing a challenge with handling exceptions properly when submitting in redux forms. I want to display a toast message when an error occurs. LogIn.js: class LogIn extends PureComponent { onSubmit = (values) => { const { login } = this.props; ...

Is it possible to use a Jasmine spy on a fresh instance?

In need of assistance with testing a TypeScript method (eventually testing the actual JavaScript) that I'm having trouble with. The method is quite straightforward: private static myMethod(foo: IFoo): void { let anInterestingThing = new Interesti ...

Open a submenu when clicking on an input field and automatically close it when the focus is lost

Is there an easier way to create a submenu that opens on input click and closes when losing focus using jQuery? Right now, I have achieved this functionality with the following code: $(document).mouseup(function (e){ var container = $(".container"); ...

Harnessing the power of two-way data binding in VueJS

I am looking to utilize Vue's two-way data binding to dynamically update the values of amount and total. The price of a given product is fixed. When users modify the amount, the total = amount * total will be automatically calculated. Similarly, users ...

Create an unordered Vue component object

In the data retrieved from the backend, there is an object containing various properties, one of which is the 'average' value. This object is ordered based on that value and when accessed through Postman, it appears as follows: ranking: ...

Is there a framework available to animate Pseudo CSS elements?

Recently, I was working on developing a bar chart that utilized pseudo CSS elements (::before, ::after). While I successfully created bars that look visually appealing, I encountered a challenge when attempting to animate the height changes. Whenever I us ...

Transforming color images into black and white using JavaScript

     I have implemented this code to convert colored images to grayscale. function applyGrayscaleEffect() {         var imageData = contextSrc.getImageData(0, 0, width, height);         var data = imageData.data;         var p1 = 0.99;   ...

Refreshing a page following an AJAX request made with jQuery

I am working on a JSP page that shows student details. When a student is selected from the dropdown box, it triggers an onchange event to retrieve the minimum and maximum marks for that student. <form name="listBean"> <c:forEach var="Item" i ...

Error: Unable to locate module: Issue discovering 'crypto' and 'fs' modules

I am currently in the process of learning React and attempting to establish a connection between my React app and my database using the following code: var mysql = require('mysql'); var con = mysql.createConnection({ host: "localhost", user: ...

Memory leaks observed in BinaryJS websockets

Currently, I am in the process of developing a simple client/server setup to facilitate the transfer of image data between a browser and a node.js server using BinaryJS websockets. Despite following the API examples closely, it seems that my implementatio ...

Creating a visually appealing chart similar to Excel can be achieved using JavaScript with a whopping 64382 lines of JSON data. No need for Chart.js or any additional tools - simply rely on JavaScript, HTML, and CSS to

I have a project that is due in just a few hours and I need to create a detailed chart using a large set of 64382 lines of JSON data. My knowledge of javascript is limited, so I am struggling to come up with ideas on how to approach this task. While I have ...

How to smoothly fade out content when hovering over a menu item in HTML<li> tags

Hi there, I have encountered a problem and could really use your assistance. I am attempting to create a menu that displays content when you hover over an li tag. The first content should always be visible when hovering over the first li option or if no l ...

Issues encountered while utilizing Bliss as the template engine in NodeJS/Express

Seeking assistance in transitioning from Jade to Bliss as the template engine for a basic Express web application on NodeJS. Here is the code snippet from app.js: var express = require('express'), routes = require('./routes'), ...