Home > OS >  How to display country names on globe d3.js
How to display country names on globe d3.js

Time:05-19

I'm currently working with d3.js and basically want to display a globe, which when hovering over the individual countries displays the names in a div. But at the moment I can't output the names, respectively I don't know exactly how to access the names so I can output them in the mouseover.

What do I have to consider here? I would like to output the name of the country from the csv file.

Here is my globe:

// 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
const data = new Map();
const colorScale = d3.scaleThreshold()
  .domain([100000, 1000000, 10000000, 30000000, 100000000, 500000000])
  .range(d3.schemeBlues[8]);

// 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.code,  d.pop)
})]).then(function(loadData){
    let topo = loadData[0]

    let mouseOver = function(d) {
    d3.selectAll(".Country")
      .style("opacity", .5)
    d3.select(this)
      .style("opacity", 1)
      .style("stroke", "black")
  }

  let mouseLeave = function(d) {
    d3.selectAll(".Country")
      .style("opacity", .8)
    d3.select(this)
      .style("stroke", "transparent")
  }

  // Draw the map
  svg.append("g")
    .selectAll("path")
    .data(topo.features)
    .enter()
    .append("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);
      })
      .style("stroke", "transparent")
      .attr("class", function(d){ return "Country" } )
      .style("opacity", .8)
      .on("mouseover", mouseOver )
      .on("mouseleave", mouseLeave )

})
<!DOCTYPE html>
<meta charset="utf-8">

<!-- Load d3.js -->
<script src="https://d3js.org/d3.v6.js"></script>

<!-- Create an element where the map will take place -->
<svg id="my_dataviz" width="400" height="300"></svg>

CodePudding user response:

One approach is pushing the CSV names into the geoJSON objects. For instance:

loadData[1].forEach(row => {
    const foundGeometry = loadData[0].features.find(e => e.id === row.code);
    if (foundGeometry) foundGeometry.properties.countryName = row.name;
});

Then, supposing you have a div, just do:

div.html(d.properties.countryName);

Pay attention to the fact that this is D3 v6, so the datum needs to be the second argument in your mouseOver function:

let mouseOver = function(event, d) {

Here is your code with those changes:

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

const div = d3.select("#mydiv");

// 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
const data = new Map();
const colorScale = d3.scaleThreshold()
  .domain([100000, 1000000, 10000000, 30000000, 100000000, 500000000])
  .range(d3.schemeBlues[8]);

// 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.code,  d.pop);
    return d;
  })
]).then(function(loadData) {

  let topo = loadData[0];

  loadData[1].forEach(row => {
    const foundGeometry = loadData[0].features.find(e => e.id === row.code);
    if (foundGeometry) foundGeometry.properties.countryName = row.name;
  });

  let mouseOver = function(event, d) {

    div.html(d.properties.countryName)
    d3.selectAll(".Country")
      .style("opacity", .5)
    d3.select(this)
      .style("opacity", 1)
      .style("stroke", "black")
  }

  let mouseLeave = function(d) {
    div.html(null)
    d3.selectAll(".Country")
      .style("opacity", .8)
    d3.select(this)
      .style("stroke", "transparent")
  }

  // Draw the map
  svg.append("g")
    .selectAll("path")
    .data(topo.features)
    .enter()
    .append("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);
    })
    .style("stroke", "transparent")
    .attr("class", function(d) {
      return "Country"
    })
    .style("opacity", .8)
    .on("mouseover", mouseOver)
    .on("mouseleave", mouseLeave)

})
#mydiv {
  height: 1.2em;
}
<!DOCTYPE html>
<meta charset="utf-8">

<!-- Load d3.js -->
<script src="https://d3js.org/d3.v6.js"></script>

<!-- Create an element where the map will take place -->
<div id="mydiv"></div>
<svg id="my_dataviz" width="400" height="300"></svg>

  • Related