1028
1028

Reputation: 129

d3 skips first index in an array when appending circles

I'm new to using D3 and I'm trying to evenly place circles around another circle by dividing into n pieces. The problem is that it does not draw the first circle even though coords[0] exists. Instead it places starts at coords[1] and continues. Any reason why this is and how to fix it?

main.html

<!doctype html>
<html>
    <head>
        <title>A Circle</title>
        <meta charset="utf-8" />
        <script type="text/javascript" src="https://d3js.org/d3.v4.min.js"></script>
        <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mathjs/3.16.1/math.min.js"></script>
    </head>
    <body>
        <script type="text/javascript" src="circle.js"></script>
    </body>
</html>

circle.js

    var w = 500;
    var h = 500;
    var n = 10;
    var r = h/2-20;
    var coords = [];

    for (var i = 0; i<n; i++)
    {
        var p_i = {};
        p_i.x = w/2+r*math.cos((2*math.pi/n)*i);
        p_i.y = h/2-r*math.sin((2*math.pi/n)*i);
        coords.push(p_i);
    }


    var svg = d3.select('body') //SVG Canvas
        .append('svg')
        .attr('width', w)
        .attr('height', h);

    var circle = svg.append('circle') //Draw Big Circle
        .attr('cx', w/2)
        .attr('cy', h/2)
        .attr('r', r)
        .attr('fill', 'teal')
        .attr('stroke', 'black')
        .attr('stroke-width', w/100);

    var center = svg.append('circle') //Construct Center
        .attr('cx', w/2)
        .attr('cy', h/2)
        .attr('r', r/50)
        .attr('fill', 'red')
        .attr('stroke', 'black')
        .attr('stroke-width', w/100);

    var approx_pts = svg.selectAll('circle')
        .data(coords, function(d)
              {
                  return this.id;
              })
        .enter()
        .append('circle')
        .attr('cx', function(d)
              {
                  return d.x;
              })
        .attr('cy', function(d)
              {
                  return d.y;
              })
        .attr('r', w/100)
        .attr('fill', 'black');

Upvotes: 1

Views: 412

Answers (1)

Gerardo Furtado
Gerardo Furtado

Reputation: 102219

You already have circles in the SVG when you do this:

var approx_pts = svg.selectAll('circle')

Therefore, your "enter" selection has less elements than your data array.

Solution: just use selectAll(null):

var approx_pts = svg.selectAll(null)

That way you can be sure that your enter selection has all the elements in your data array. Of course, this approach avoids creating an "update" and "exit" selections in the future.

If you do plan to use an "update" and "exit" selections, you can select by class:

var approx_pts = svg.selectAll(".myCircles")

Don't forget to set that class when you append those circles in the enter selection, of course.

Upvotes: 2

Related Questions