D4r1 D4r1 - 9 days ago 5
Javascript Question

Tooltip on d3.geo.circle mousedown always displays last line of CSV file

I'm building a map with a few d3.geo.circle on it (with d3.v3.min.js). Once you click on a circle, the data attached to it should be displayed in a custom CSS tooltip. However, even though the d3.geo.circle are displayed on the map, the tooltip always displays the last line of my CSV file whichever circle you click on.

Here is a snippet of my code :

d3.json("json/world-countries.json", function(collection) {
var countries = svg.selectAll("path")
.data(collection.features)
.enter().append("path")
.attr("class", "boundary")
.attr("id", function(d) {return d.id;})
.attr("d", path);

d3.csv("csv/object-data.csv", function(data) {
var dots = svg.selectAll("dots")
.data(data)
.enter().append("path")
.attr("class", "dots")
.datum(function(d) {return d3.geo.circle().origin([ d.longitude, d.latitude ]).angle(d.radius)();})
.attr("d", path);

data.forEach(function(d) {
id = +d.id;
name = d.name;

dots.on("mousedown", function(d) {
d3.select("#ObjectID").html('<div class="box-title"><strong>Object ID</strong></div>'
+ '<table><tr><td>Project name</td><td>' + name);


The CSV file looks like this :

id,longitude,latitude,radius,name
0,2.343333,48.848611,1,Paris
1,-0.126267,51.507548,0.987230769,London


I checked through console.log(id); and always get the last line, whichever geo.circle the user clicks on. This means that dots.on("mousedown") always returns the last line, and not the one corresponding to the relevant circle. At the same time, if I used countries.on("mousedown") and check for console.log(d.id), I would get the ID of the country on the map I would be clicking on.

Here are my questions :


  • Why does it implicitely looks like to be working for a geographic JSON file and not for a CSV file ? Any link with the fact that d3.geo is involved ?

  • How do I make this work ? As in, how do I make sure once the user clicks a circle, the data corresponding to this precise circle is displayed, and not the last one in the list ?

  • What did I miss, conceptually speaking ? It feels like something very obvious I keep not thinking of.


Answer

OK so I found the solution.

First, you need to create a variable and push data inside.

    var projectdata = [];
    data.forEach(function(e,i) {
            projectdata.push({
            id : e.id,
            name : e.name,});});

Then you need to return the id of each dot clicked and make it correspond to the relevant data.

    var dots = svg.selectAll("dots")
                          .data(data)
                          .enter().append("path")
                            .attr("id", function(d) {return d.id;})
                            .attr("class", "dots")
                            .datum(function(d) {return d3.geo.circle().origin([ d.longitude, d.latitude ]).angle(d.radius)();})
                            .attr("d", path)
                            .on("mousedown", function(d) {
                            var i = this.id-1;
                            d3.select("#ObjectID").html('<div class="box-title"><strong>Object ID</strong></div>'
                        +  '<table><tr><td>Project name</td><td>' + projectdata[i].name);

And that does the trick! Will post the result once it is online. Special thanks to @elias and @pwetosaurus, questions made me change my perspective on the problem.

Comments