Search code examples
javascriptd3.jsd3-force-directed

D3 mouseover return name


Hi I'm pretty new to d3 and I'm trying to add text on hover/mouseover when I'm making chart. Can anyone please suggest a way to implement it? I have tried many options like creating a div variable to select div id, appending a title to circle and giving a text but nothing worked so far.

Here is my js code:

  var width = 900,
    height = 500;

  var svg = d3.select("#chart")
    .append("svg")
    .attr("height", height)
    .attr("width", width)
    .append("g")
    .attr("transform", "translate(" + width/2+"," + height/2 +")")

  var defs = svg.append("defs");

  defs.append("pattern")
    .attr("id", "flag")
    .attr("height", "100%")
    .attr("width", "100%")
    .attr("patternContentUnits", "objectBoundingBox")
    .append("image")
    .attr("height", 1)
    .attr("width", 1)
    .attr("preserveAspectRatio", "none")
    .attr("xmlns:xlink", "http://www.w3.org/1999/xlink")
    .attr("xlink:href", "images/usa.gif");

  var radiusScale = d3.scaleSqrt().domain([0, 61000]).range([5, 40])

  // the simulation is a collection of forces
  // about where we want our circles to go
  // and how we want our circles to interact
  // STEP ONE: get them to the middle
  // STEP TWO: don't have them collide!!!
  var simulation = d3.forceSimulation()
    .force("x", d3.forceX().strength(0.05))
    .force("y", d3.forceY().strength(0.05))
    .force("collide", d3.forceCollide(function(d) {
      return radiusScale(d.casualities) + 1;
    }))


  d3.csv("sub_country.csv ").then(ready)

  function ready (datapoints) {


    defs.selectAll(".flag-pattern")
      .data(datapoints)
      .enter().append("pattern")
      .attr("class", "flag-pattern")
      .attr("id", function(d) {
          return d.Country 
      })
      .attr("height", "100%")
      .attr("width", "100%")
      .attr("patternContentUnits", "objectBoundingBox")
      .append("image")
      .attr("height", 1)
      .attr("width", 1)
      .attr("preserveAspectRatio", "none")
      .attr("xmlns:xlink", "http://www.w3.org/1999/xlink")
      .attr("xlink:href", function(d) {
        return d.image_path
      });


    var circles = svg.selectAll(".Country")
      .data(datapoints)
      .enter().append("circle")
      .attr("class", "Country")  
      .attr("r", function(d) {
        return radiusScale(d.casualities);
      })
      .on('click', function(d) {
        console.log(d)
      })
      .attr("fill", function(d) {
        return "url(#" + d.Country + ")"
      })


    simulation.nodes(datapoints)
      .on('tick', ticked)

    function ticked() {
      circles
        .attr("cx", function(d) {
          return d.x
        })
        .attr("cy", function(d) {
          return d.y
        })

            }

  }

})();

The data looks like this:

Country,casualities,image_path
algeria,4760,images/algeria.jpg
bahrain,67,images/bahrain.jpg
canada,48,images/canada.png
egypt,5129,images/egypt.png
international,13,images/international.png
iran,1210,images/iran.png
iraq,74473,images/iraq.png
israel,5129,images/israel.png
jordan,278,images/jordan.png

Thanks in advance!


Solution

  • I have updated your code snippet with tool-tips using svg title. Not sure why it didn't work for you.

    You can compare your trial code with the snippet to find the root cause.

    var width = 500,
      height = 300;
    
    var svg = d3.select("#chart")
      .append("svg")
      .attr("height", height)
      .attr("width", width)
      .append("g")
      .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")")
    
    var defs = svg.append("defs");
    
    defs.append("pattern")
      .attr("id", "flag")
      .attr("height", "100%")
      .attr("width", "100%")
      .attr("patternContentUnits", "objectBoundingBox")
      .append("image")
      .attr("height", 1)
      .attr("width", 1)
      .attr("preserveAspectRatio", "none")
      .attr("xmlns:xlink", "http://www.w3.org/1999/xlink")
      .attr("xlink:href", "images/usa.gif");
    
    var radiusScale = d3.scaleSqrt().domain([0, 61000]).range([5, 40])
    
    // the simulation is a collection of forces
    // about where we want our circles to go
    // and how we want our circles to interact
    // STEP ONE: get them to the middle
    // STEP TWO: don't have them collide!!!
    var simulation = d3.forceSimulation()
      .force("x", d3.forceX().strength(0.05))
      .force("y", d3.forceY().strength(0.05))
      .force("collide", d3.forceCollide(function(d) {
        return radiusScale(d.casualities) + 1;
      }));
    
    
    var datapoints = [{
        "Country": "algeria",
        "casualities": 4760,
        "image_path": "images/algeria.jpg"
      },
      {
        "Country": "bahrain",
        "casualities": 67,
        "image_path": "images/bahrain.jpg"
      },
      {
        "Country": "canada",
        "casualities": 48,
        "image_path": "images/canada.png"
      },
      {
        "Country": "egypt",
        "casualities": 5129,
        "image_path": "images/egypt.png"
      },
      {
        "Country": "international",
        "casualities": 13,
        "image_path": "images/international.png"
      },
      {
        "Country": "iran",
        "casualities": 1210,
        "image_path": "images/iran.png"
      },
      {
        "Country": "iraq",
        "casualities": 74473,
        "image_path": "images/iraq.png"
      },
      {
        "Country": "israel",
        "casualities": 5129,
        "image_path": "images/israel.png"
      },
      {
        "Country": "jordan",
        "casualities": 278,
        "image_path": "images/jordan.png"
      }
    ];
    
    
    defs.selectAll(".flag-pattern")
      .data(datapoints)
      .enter().append("pattern")
      .attr("class", "flag-pattern")
      .attr("id", function(d) {
        return d.Country
      })
      .attr("height", "100%")
      .attr("width", "100%")
      .attr("patternContentUnits", "objectBoundingBox")
      .append("image")
      .attr("height", 1)
      .attr("width", 1)
      .attr("preserveAspectRatio", "none")
      .attr("xmlns:xlink", "http://www.w3.org/1999/xlink")
      .attr("xlink:href", function(d) {
        return "https://cdn1.iconfinder.com/data/icons/major-world-flags-1/512/india_flag_circle-512.png"
      });
    
    
    var circles = svg.selectAll(".Country")
      .data(datapoints)
      .enter().append("circle")
      .attr("class", "Country")
      .attr("r", function(d) {
        return radiusScale(d.casualities);
      })
      .on('click', function(d) {
        console.log(d)
      })
      .attr("fill", function(d) {
        return "url(#" + d.Country + ")"
      });
      
    circles.append("svg:title")
      .text(function(d, i) {
        return d.Country
      });
    
    
    simulation.nodes(datapoints)
      .on('tick', ticked)
    
    function ticked() {
      circles
        .attr("cx", function(d) {
          return d.x
        })
        .attr("cy", function(d) {
          return d.y
        })
    
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
    <div id="chart"></div>