4

enter image description hereI am working on a project to have multiple paths representing routes a map. I am following this d3 nest example group my data by a key to create multiple routes.

I would like to animate a circle element to transition along each separate route path. I can see that my problem is very much like this example and this solution but I don't understand how to apply the solution to my example.

I can’t understand how to get the index / key of my groups into the createPathTween function. So I have just one circle element on the first of my groups rather than a circle element transitioning along each route /path. Can someone please help me work out how to place the transitioning circle element on each route path?

This is my d3 code

<html>
<head>
    <title>Hello</title>
    <script src="http://d3js.org/d3.v4.min.js" charset="utf-8"></script>

    <style>

        }
        .placeVisited{
          fill:#999;
        }

        .journey{
          fill: none;
        }

    </style>
</head>
<body>

<script>

  var width = 1200;
  var height = 550;

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

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

  var projection = d3.geoMercator()
    .center([55, 12])
    .scale(220)
    .translate([width/2,height/2])

  var geoPath = d3.geoPath()
    .projection(projection);

  var voyageLine = d3.line()
    .x(function(d) { return projection([d.lon,d.lat])[0] ; })
    .y(function(d) { return projection([d.lon,d.lat])[1]; })
    .curve(d3.curveBasis);

  var parseDate = d3.timeParse("%d %B %Y");
  var parseYear = d3.timeParse("%Y");


  var color = d3.scaleOrdinal(d3.schemeCategory10);

d3.queue()
  .defer(d3.csv, "multipleVoyages2.csv")
    .await(ready);

function ready (error, data){

  data.forEach(function(d) {
    d.year = parseYear(d.year);
    d.lon= +d.lon;
    d.lat = +d.lat;
  });

var dataNest = d3.nest()
    .key(function(d){return d.VoyageID;})
    .entries(data);

var journey = g.selectAll(".journey")
    .data(dataNest)
    .enter()
    .append("path")
    .attr("class", "journey")
    .style("stroke", function(d) {
      return d.color = color(d.key); })
    .attr("d", function(d){
      return voyageLine(d.values);
    })
    .attr("stroke-dasharray", function() {
        var totalLength = this.getTotalLength();
        return totalLength + " " + totalLength;
            })
    .attr("stroke-dashoffset", function() {
        var totalLength = this.getTotalLength();
        return totalLength;
            })
    .transition()
    .ease(d3.easeLinear)
    .duration(5000)
    .attr("stroke-dashoffset", 0);


var marker = g.append("circle")
      .attr("r", 7)
      .style("fill", "pink")
      .attr("transform", "translate(-100,-100)")
        .transition()
        .ease(d3.easeLinear)
        .duration(5000)
        .attrTween("transform", createPathTween);


var placeGroups = g.selectAll(".placeVisited")
    .data(dataNest)
    .enter()
    .append( "g" )
    .attr("class","placeVisited");

var placeVisited = placeGroups.selectAll("placeVisited")
    .data(function(d){
    return d.values;
  })
    .enter()
    .append("circle")
    .attr("fill", function(d){
      return d.color = color(d.VoyageID);
    })
    .attr("cx", function(d, i) {
      return projection([d.lon, d.lat])[0];

    })
    .attr("cy", function(d, i) {
            return projection([d.lon, d.lat])[1];

    })
    .attr("r", 5)

//transitioning marker

//from this example -- http://fiddle.jshell.net/RnNsE/2/
function createPathTween(d, i, a) {
  // var path = this.parentNode.getElementsByTagName("journey")[0];
   var path = this.parentNode.getElementsByClassName("journey")[i]; //don't understand how to get the index for each group
    var l = path.getTotalLength();
    console.log("path");
    console.log(path);

    return function(t) {
        var p = path.getPointAtLength(t * l);
        return "translate(" + p.x + "," + p.y + ")";
      };

}
}
    </script>
</body>
</html>

and my csv:

VoyageID,VoyageType,voyageName,ObjectID,arrivalDateTxt,year,ObjectNumber,placeName,lon,lat,url,,,
1,Pleasure cruise,Postcards home,170207,14 January 1906,1906,ANMS1113[006],Port Pirie,138.16,-33.183,http://collections.anmm.gov.au/en/objects/details/170207/,,,
1,Pleasure cruise,Postcards home,170205,1 May 1907,1907,ANMS1113[004],Mount Lofty Ranges,138.6,-34.933,http://collections.anmm.gov.au/en/objects/details/170205/,,,
1,Pleasure cruise,Postcards home,170216,26 October 1907,1907,ANMS1113[015],Brisbane,153,-27.5,http://collections.anmm.gov.au/en/objects/details/170216/,,,
1,Pleasure cruise,Postcards home,170200,4 November 1907,1907,ANMS1113[001],Adelaide,138.6,-34.933,http://collections.anmm.gov.au/en/objects/details/170200/,,,
1,Pleasure cruise,Postcards home,170213,26 November 1907,1907,ANMS1113[012],Fremantle,115.766,-32.5,http://collections.anmm.gov.au/en/objects/details/170213/,,,
1,Pleasure cruise,Postcards home,170209,3 December 1907,1907,ANMS1113[008],Adelaide,138.6,-34.933,http://collections.anmm.gov.au/en/objects/details/170209/,,,
1,Pleasure cruise,Postcards home,170212,10 December 1907,1907,ANMS1113[011],Melbourne,144.966,-37.75,http://collections.anmm.gov.au/en/objects/details/170212/,,,
1,Pleasure cruise,Postcards home,170217,20 December 1907,1907,ANMS1113[016],Sydney,151.166,-33.916,http://collections.anmm.gov.au/en/objects/details/170217/,,,
1,Pleasure cruise,Postcards home,170203,26 December 1907,1907,ANMS1113[002],Brisbane,153,-27.5,http://collections.anmm.gov.au/en/objects/details/170203/,,,
1,Pleasure cruise,Postcards home,170215,26 December 1907,1907,ANMS1113[014],Brisbane,153,-27.5,http://collections.anmm.gov.au/en/objects/details/170215/,,,
1,Pleasure cruise,Postcards home,170211,8 January 1908,1908,ANMS1113[010],Port Pirie,138.16,-33.183,http://collections.anmm.gov.au/en/objects/details/170211/,,,
1,Pleasure cruise,Postcards home,170208,14 January 1908,1908,ANMS1113[007],Port Pirie,138.16,-33.183,http://collections.anmm.gov.au/en/objects/details/170208/,,,
2,Kayak adventure,Oskar,1,1 March 1961,1961,,London,-0.127758,51.507351,,,,
2,Kayak adventure,Oskar,2,2 April 1961,1961,,Paris,2.352222,48.856614,,,,
2,Kayak adventure,Oskar,3,3 June 1961,1961,,Lyon,4.835659,45.764043,,,,
2,Kayak adventure,Oskar,4,28 June 1961,1961,,Calais,1.858686,50.95129,,,,
2,Kayak adventure,Oskar,5,10 July 1961,1961,,Frankfurt,8.682127,8.682127,,,,
2,Kayak adventure,Oskar,6,19 December 1961,1961,,Berlin,13.404954,52.520007,,,,
2,Kayak adventure,Oskar,7,25 January 1962,1962,,Amsterdam,4.895168,52.370216,,,,
2,Kayak adventure,Oskar,8,30 June 1962,1962,,rome,12.496366,41.902783,,,,
2,Kayak adventure,Oskar,9,24 November 1962,1962,,Milan,9.189982,45.464204,,,,
2,Kayak adventure,Oskar,10,19 January 1963,1963,,Turin,7.686856,45.070312,,,,
2,Kayak adventure,Oskar,11,27 January 1963,1963,,Florence,11.255814,43.76956,,,,
2,Kayak adventure,Oskar,12,30 April 1963,1963,,Vienna,16.373819,48.208174,,,,
3,Whaling ,Barque Terror,123,12 March 1845,1845,,Island 1,155.370833,-24.916667,,,,
3,Whaling ,Barque Terror,777,15 March 1845,1845,,Island 2,162.81738,-20.6739,,,,
3,Whaling ,Barque Terror,546,22 March 1845,1845,,Place in ocean 3,160.26464,-11.66325,,,,
3,Whaling ,Barque Terror,888,23 July 1845,1845,,Place in ocean 4,161.94638,-10.18388,,,,
3,Whaling ,Barque Terror,543,19 December 1845,1845,,Place in ocean 5,160.90712,-8.94461,,,,
3,Whaling ,Barque Terror,2134,22 January 1846,1846,,Place in ocean 6,158.74232,-9.01835,,,,
3,Whaling ,Barque Terror,6666,30 January 1846,1846,,Back home,157.26555,-8.19361,,,,
user3471259
  • 215
  • 1
  • 15
  • So, you want just **one** circle moving along a path and then, when that path finishes, that circle starts moving along another path, is that correct? Also, you have a lot of code/data here. A better idea is creating a running example using [blockbuilder](http://blockbuilder.org/), that way we can just change the function. – Gerardo Furtado May 14 '18 at 12:20
  • @GerardoFurtado - thank you very much for your response and advice on a better way to post my code. I wasn't aware of block builder but will try it next time I am hoping for help here. – user3471259 May 15 '18 at 09:12

1 Answers1

1

You can get the paths to animate after one has finished using the delay function for both your path as well as your marker like so:

.duration(5000)
.delay(function(d, i) { // 'i' will give you the index
    return i * 5000; // Multiply by 5000 so that it starts after the previous one has finished.
});

and to get a circle marker for every path, you need to create the same number of circles like this:

var marker = g.selectAll('circle')
            .data(dataNest).enter()
            .append("circle")...

Also use d3.curveCatmullRom for a better path.

Here's a plunker

Aditya
  • 1,357
  • 1
  • 9
  • 19
  • OP wants to animate circle/circles along the path, not animating the path itself. – Gerardo Furtado May 14 '18 at 12:49
  • @GerardoFurtado Oh my bad.. I've updated the plunker now. Thanks. – Aditya May 14 '18 at 13:01
  • Brilliant - thank you so much for your help. this is exactly what I was hoping to achieve @AdityaK. – user3471259 May 15 '18 at 09:03
  • @user3471259 Glad I could help! – Aditya May 15 '18 at 09:04
  • Brilliant - thank you so much for your help @AdityaK. This is exactly what I was hoping to achieve - particularly the way to get a circle for each separate path using the dataNest data. – user3471259 May 15 '18 at 09:12
  • @user3471259 You can also add the code: `.on('end',function(d){d3.select(this).remove();});` after the `attrTween` function of your `markers` if you want to remove the pink circles once the animation has ended. – Aditya May 15 '18 at 09:20
  • Thank you @AdityaK - your comment is helpful - there is a lot for me to learn and this is really useful. – user3471259 May 15 '18 at 09:57