D3: Can I convert svg based on the items in the list?

I would like to take a list ...

var data = [100, 200, 300] // arbitrarily long

      

... and move the item around the screen based on each item in the list. For example, I would like to first send a point to [100, 100], [200, 100], [300, 100]. Is there a way to do this when connecting data?

I currently have a solution that works, but it works in what seems to be a very non-D3-ish way: using a counter to iterate over a list and using data binding. Excluding CSS, here's the code:

<svg>
  <circle/>
</svg>


<script>

var data = [100,200,300]

var circle = d3.selectAll("circle")
    .attr("r",20)
    .attr("cy",100)
    .attr("cx",0)

var count = 0

repeat()

function repeat() {
  var run = circle
    .transition()
    .duration(1000)
    .attr("cx", function (d) {return data[count]});

    count++

  if (count < data.length){
    run
      .each("end", repeat);
  }   
}

</script>

      

Should there be a way to do this with data binding? I would like to do it right, but for now this is all I can figure out to get it to work.

+3


source to share


2 answers


Using this as a link: https://bl.ocks.org/mbostock/1125997

I'm not sure if this is the best way to do it, because it still relies on an external variable count

which is not very D3.

Pay attention to the structure of the array data

.

https://jsfiddle.net/e51rzkth/4/



var data = [[[100,100],[200,100],[300,100]]]

var svg = d3.select("body")
    .append("svg")
  .attr("width", 400)
  .attr("height", 400)

var circle = svg.selectAll("circle")
  .data(data)
  .enter()
  .append("circle")
    .attr("r",20)
    .style("fill", "red")

var count = 0

circle
    .transition()
    .duration(1000)
    .delay(250)
    .on("start", function repeat() {
        d3.active(this)
          .transition()
          .attr('cx', d=>d[count][0])
          .attr('cy', d=>d[count][1])
          .transition()
            .on("start", repeat);
            count++;
      });

      

For funsies, an example with several circles, each with its own path.

https://jsfiddle.net/e51rzkth/3/

+1


source


Yes, you can enter / add circles based on the data in the array and then set the cx based on the data. Alternatively, you can achieve overwhelm by basing the transition delay on the data point index, like https://jsfiddle.net/65aeo5q5/ :



var circle = svg.selectAll("circle")
  .data(data)
  .enter()
  .append("circle")
    .attr("r",20)
    .attr("cy",100)
    .attr("cx",0)
    .style("fill", "red")

var delay = 1000;

circle
    .transition()
    .duration(delay)
    .delay(function (d, i) {return i * delay;})
    .attr("cx", function (d) {return d;});

      

0


source







All Articles