d3.js selectAll().each on svg path.. undefined?

28,787

Solution 1

Simplifying your original request, let's suppose you want to add a circle in the center of each district. Let's assume that the districts are relatively square. Note that this would be much more simpler if you have geographical data instead of paths.

var svg = d3.select("#somediv svg");
var districts = svg.selectAll("path");

var district_centers = districts[0].map(function(d, i) {
    var bbox = this.getBBox();
    return [bbox.left + bbox.width/2, bbox.top + bbox.height/2];
});

svg
  .selectAll("circle")
  .data(district_centers)
  .enter()
  .append("circle")
     .attr("class", "district_circle")
     .attr("cx", function(d){ return d[0]})
     .attr("cy", function(d){ return d[1]})
     .attr("r", 10)
     .attr("fill", "red");

Solution 2

According to the API doc for selection.each, d should be the datum, which you will not have if you have not previously called .data() to bind data to the nodes. All you have is pure SVG with no data bound to it.

I notice that your paths do have IDs, so if you have a dataset matching those ID's you can probably bind to it using the keys parameter of the .data function

Share:
28,787
nkint
Author by

nkint

recursive: adjective, see recursive.

Updated on July 09, 2022

Comments

  • nkint
    nkint almost 2 years

    I'm importing a svg (served as static content from the server) in this way

    d3.xml("http://localhost:3000/mysvg.svg", "image/svg+xml", function(xml) {
        var importedNode = document.importNode(xml.documentElement, true);
        var mySvg = d3.select("#somediv").node().appendChild(importedNode);
    

    then I'm trying to iterate through all svg paths and do something with them

        d3.selectAll("#somediv svg path").each(function(d, i) {
            console.log(this, d, i);
        });
    }
    

    what I'm getting is this problem

    • i is from 1 to number of path, which is correct.

    • d is undefined instead of being the right svg path element.

    • this is the svg path element, like this one

      <path id="m021" fill="#00AAFF" d="M225.438,312.609c-0.665-1.084-1.062-1.691-2.368-1.963c-0.582-0.121-1.686-0.271-2.265-0.069 c-0.507,0.174-0.637,0.649-1.431,0.368c-0.934-0.33-0.665-1.272-0.71-2.104c-0.597-0.021-1.18,0-1.733,0.262 ...etc" ></path>

    I expected d to be the real svg path, why is it not?

    EDIT:

    A little insight on what I want to do could maybe help.

    I have a svg with one path for each district of my town. I want to make some piecharts in the center of each path. I don't have the data now, it will be used for the piecharts. I want to make a mouseover function on the path, and add a little red circle (that in a future step will become the pie chart) on each path.

    What is the best way to do this?

  • nkint
    nkint over 11 years
    ok, that's clear! i have to investigate a bit on geographical data!
  • nkint
    nkint over 11 years
    i've read the manual and your code seems good but when i write console.log(district_centers[0]); i get an array of path#m110.[object SVGAnimatedString]
  • methodofaction
    methodofaction over 11 years
    @nkint sorry, should have been each as you had it initially.
  • nkint
    nkint over 11 years
    same things. i have to create an array and push manually. the returned array from selection.each() does not contains any data (o i can't figure where). i have to do something like: var svg = d3.select("#somediv svg"); var districts = svg.selectAll("path"); var district_centers = []; districts.each(function(d, i) { var bbox = this.getBBox(); district_centers.push( [bbox.left + bbox.width/2, bbox.top + bbox.height/2] ); }); that doenn't sound so good
  • methodofaction
    methodofaction over 11 years
    @nkint Gah, the syntax changed in D3 v3 so the syntax has me confused, this latest edit will work for sure.