1

Inspired by https://www.nytimes.com/interactive/2018/03/19/upshot/race-class-white-and-black-men.html

I am trying to create a animation that will have markers move from one point to multiple levels in another point in the y axis. Thanks to detailed pages by Amelia and Mike Bostock in both bl.ocks.org and stackoverflow. I have got so far to get the circles and animate it. But, I am not able to make each marker loop over by the pathlevel and do the transition

Pathlevel, here, indicates whether they are high, middle or low (1,2,3).

The entire code in using d3.v4 has been pasted below. what I am missing?

Thanks for your help.

<!DOCTYPE html>
<meta charset="utf-8">
<title>SANKEY Experiment</title>
<style>

</style>
<body>

<script type="text/javascript" src="d3.v4.js"></script>

<script>

 
 //ref: very important for path animation: https://stackoverflow.com/questions/21226523/trace-path-with-dom-object/21228701#21228701
 //ref: clustered force layout: https://bl.ocks.org/mbostock/7881887
 //ref: data manipulation: http://learnjsdata.com/iterate_data.html
 var margin = {top: 30, right: 10, bottom: 30, left: 20},
  width = 500 - margin.left - margin.right,
  height = 500 - margin.top - margin.bottom;

 var series = [{x:5,y:10},{x:150,y:10}],
  series2 = [{x:5,y:10},{x:50,y:15},{x:100,y:30},{x:150,y:30}],
  series3 = [{x:5,y:10},{x:50,y:22},{x:100,y:50},{x:150,y:50}];
 
 
   
 var data = [{"dim":"a","pos":"high","pathlevel":1,"x1":1,"y1":10,"x2":150,"y2":8},
 {"dim":"b","pos":"high","pathlevel":1,"x1":1,"y1":10,"x2":150,"y2":8},
 {"dim":"a","pos":"mid","pathlevel":2,"x1":1,"y1":10,"x2":150,"y2":28},
 {"dim":"b","pos":"mid","pathlevel":2,"x1":1,"y1":10,"x2":150,"y2":28},
 {"dim":"a","pos":"low","pathlevel":3,"x1":1,"y1":10,"x2":150,"y2":48},
 {"dim":"b","pos":"low","pathlevel":3,"x1":1,"y1":10,"x2":150,"y2":48}]

 var x = d3.scaleLinear()
    .domain([5,150])
    .range([0,width]);

 var y = d3.scaleLinear()
    .domain([10,50])
    .range([0,height]);
    
 var line = d3.line()
  .curve(d3.curveCardinal)
  .x(function(d) { return x(d.x); })
  .y(function(d) { return y(d.y); });
   var svg = d3.select("body").append("svg").attr("height",600).attr("width",600);

 var chart = svg.append("g").attr("transform","translate("+margin.left+","+margin.top+")");
 
 
 var update = function(series,k){
 
 chart.append("path")
    .attr("class","route"+k) 
    .attr("fill","none")
    .attr("stroke","blue")
    .attr("d",line(series));
    }

 update(series,1);
 update(series2,2);
 update(series3,3);
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 //create transistions along the path //////////////////////////////////////////////////////////////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
 
 
 var colorScale = d3.scaleOrdinal()
     .domain(['a','b'])
     .range(['orange','darkblue']);
     
 //Get path start point for placing marker
 var path = d3.select('.route1')
 var startPoint = path.attr("d").split(",")[1];
 //path example["M12.885906040268456", "84.48979591836735C12.885906040268456", "84.48979591836735", "241.07382550335572", "84.48979591836735", 
 //"318.9261744966443", "84.48979591836735C396.7785234899329", "84.48979591836735", "480", "84.48979591836735", "480", "84.48979591836735"]
 //selecting class route which represents the path. d represents the path that is held by the path object. in that we split by comma and take the first
 
 console.log(startPoint);
 
 
 var glider = function(data,p){//p for path level

  var marker = chart.selectAll(".marker")
    .data(data)
    .enter().append('circle')
    .attr("class","marker")
    .attr("fill",function(d){ return colorScale(d.dim);})
    //.attr("x",function(d,i){return x(d.x1)+i*10;})
    //.attr("y",function(d,i){return y(d.y1)+i*10;})
    .attr("r",5);
    //.attr("width",10)
    //.attr("height",10);
  
    
  var simulation = d3.forceSimulation()
     .force("x",d3.forceX().strength(0.05))
     .force("y",d3.forceY().strength(0.01))
     .force('charge', d3.forceManyBody().strength(20))
     .force("collide",d3.forceCollide(function(d){return y(d.y1)+4;}))
     .alphaTarget(.03)
     .restart();

  simulation.nodes(data)
    .on('tick',ticked);
  
  function ticked(){
   marker
   .attr("cx",function(d){ return d.x;})
   .attr("cy",function(d){ return d.y;})
  }//end of ticked
   
  //marker.transition().duration(3000).delay(200)
  //  .attr("x",function(d,i){return x(d.x2)+i*10;});

  function translateAlong(path) {
   var l = path.getTotalLength();
   return function (d) {
     return function (t) {
    var p = path.getPointAtLength(t * l);
    return "translate(" + p.x + "," + p.y + ")";//Move marker
     }
   }
  }//end of translateAlong

  console.log(marker);
  
  function transition(){
  
   var path2 = d3.select('.route'+p);
   
   marker.attr("transform", "translate(" + startPoint + ")").transition().duration(3000).delay(function(d,i) { return i * 100; })
    .attrTween("transform",translateAlong(path2.node()));
    //.attr("x",function(d,i){return x(d.x2)+i*10;});
   
  }//end of transition
  
  transition();
 }
 
 /*var check = d3.map(data, function(d){return d.pathlevel;}).keys(); //for getting unique values from a column
 
 check.forEach(function(i){
  datapoints = data.filter(function(d){return d.pathlevel==i});
  console.log(i);
  glider(datapoints,i);
  
 });*/
 
 data1 = data.filter(function(d){return d.pathlevel==1});
 data2 = data.filter(function(d){return d.pathlevel==2});
 data3 = data.filter(function(d){return d.pathlevel==3});
 
 //glider(data1,1);
 //glider(data2,2);
 glider(data3,3);
 //glider(data,2);
 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 /*function createPathTween(d, i, a) {
   var path = this.parentNode.getElementsByTagName("path")[1];
   //i.e., go from this <circle> -> parent <g> -> array of child <path> elements 
               //-> first (and only) element in that array
   //console.log(path);
   var l = path.getTotalLength();
  return function(t) {
   var p = path.getPointAtLength(t * l);
   console.log(p);
   return "translate(" + p.x + "," + p.y  + ")";
   };    
  }//end of tweenpath*/
 
</script>

</body>

0 Answers0