简体   繁体   中英

How to make d3 concurrent transitions work?

I've started doing this as a side project to learn D3. So please go easy on me;

Goal: Making an interactive airports map. When mouse is over a city planes will take off from that city's airport and land on to the destination.

Steps I've followed;

  1. I've downloaded country and airports data as geojson and defined base map on D3.

底图

  1. I've write necessary functions to derive spatial information to use in transitions. You can view code from here if you have time.
  2. I've added transitions to planes.

过渡

Problem: When I have more than one plane to take from a city it's just not moving. Instead it stays on the same position until the transition ends. I can't add concurrent transitions to the objects.

错误

My transition function is like;

function myTransition(destPoi, originPoi) {
var tr_bl = true;
pathData = []; t_dest_poi = [];
if (tr_bl) {
//Origin destination coordinates taken from the Origin Poi
originPoint[0] = originPoi[1];
originPoint[1] = originPoi[2];
originPoint = geoMercator(originPoint);//Need transformation before using on screen.
var lineGenerator = d3.line().curve(d3.curveCatmullRom);
// Destination coordinate pairs transformed to screen coordinates
// and assigned to an array 
for (i = 0; i < destPoi.length; i++) {
  t_dest_poi[i] = geoMercator(destPoi[i]);
}
//appending new group g2 with id fp 
var g2 = map_svg.append("g").attr("id", "fp");

// Creating the planes and flight paths programmatically.*************************************
for (i = 0; i < destPoi.length; i++) {
  var plane = map_svg.append("path")
    .attr("class", "plane")
    .attr("d", "m25.21488,3.93375c-0.44355,0 -0.84275,0.18332 -1.17933,0.51592c-0.33397,0.33267 -0.61055,0.80884 -0.84275,1.40377c-0.45922,1.18911 -0.74362,2.85964 -0.89755,4.86085c-0.15655,1.99729 -0.18263,4.32223 -0.11741,6.81118c-5.51835,2.26427 -16.7116,6.93857 -17.60916,7.98223c-1.19759,1.38937 -0.81143,2.98095 -0.32874,4.03902l18.39971,-3.74549c0.38616,4.88048 0.94192,9.7138 1.42461,13.50099c-1.80032,0.52703 -5.1609,1.56679 -5.85232,2.21255c-0.95496,0.88711 -0.95496,3.75718 -0.95496,3.75718l7.53,-0.61316c0.17743,1.23545 0.28701,1.95767 0.28701,1.95767l0.01304,0.06557l0.06002,0l0.13829,0l0.0574,0l0.01043,-0.06557c0,0 0.11218,-0.72222 0.28961,-1.95767l7.53164,0.61316c0,0 0,-2.87006 -0.95496,-3.75718c-0.69044,-0.64577 -4.05363,-1.68813 -5.85133,-2.21516c0.48009,-3.77545 1.03061,-8.58921 1.42198,-13.45404l18.18207,3.70115c0.48009,-1.05806 0.86881,-2.64965 -0.32617,-4.03902c-0.88969,-1.03062 -11.81147,-5.60054 -17.39409,-7.89352c0.06524,-2.52287 0.04175,-4.88024 -0.1148,-6.89989l0,-0.00476c-0.15655,-1.99844 -0.44094,-3.6683 -0.90277,-4.8561c-0.22699,-0.59493 -0.50356,-1.07111 -0.83754,-1.40377c-0.33658,-0.3326 -0.73578,-0.51592 -1.18194,-0.51592l0,0l-0.00001,0l0,0z")
    .style("opacity", 1)
    .style("fill", "transparent");
  //creating flight path data with line generator
  pathData[i] = lineGenerator([originPoint, t_dest_poi[i]]);
  //appending created flight path to variable 
  var path = g2.append("path").data([
    [originPoint],
    [t_dest_poi[i]]
  ]).attr("d", d3.line());
//flight path
  g2.selectAll('path')
    .data([
      [originPoint],
      [t_dest_poi[i]]
    ])
    .attr('d', pathData)
    .attr("stroke", "blue")
    .attr("fill", "transparent");

  plane.style("fill", "grey");

  var route = g2.append("path")
    .datum({
      type: "LineString", coordinates: [
        [originPoint],
        [t_dest_poi[i]]]
    })
    .attr("class", "route")
    .attr("d", geoPath)
    .attr("stroke", "blue")
    .attr("fill", "transparent");

  // adding transition to plane
  plane.transition()
    .duration(5000)
    .attrTween("transform", translateAlong([originPoint, t_dest_poi[i]], path.node()))
    .remove();
    }
}
else {
}}

function translateAlong(co, path) {
var l = path.getTotalLength();
return function (d, i, a) {
return function (t) {
  var p = path.getPointAtLength(t * l);
  [a1, b1] = co[0];
  [a2, b2] = co[1];
  aci = Math.atan((b2 - b1) / (a2 - a1));
  aci = aci * 180 / Math.PI;
  if (a2 > a1) {
    aci = aci + 90;
  } else {
    aci = aci - 90;
  }
  return "translate(" + (p.x) + "," + (p.y) + ") scale(" + Math.sin(Math.PI * t) + ") rotate(" + aci + ")";
};
};
}

This seems like an issue with updating the path of the #fp element during the transition. The relatively easy fix in this case is to handle the transitions separately.

In your code, in basemap.js circa line 58-63, you call myTransition() on an array of multiple elements after populating the array in a for loop.

for (i = 0; i <= n - 1; i++) {
  fp[i] = [destAirportObjects[i][1], destAirportObjects[i][2]];
}
myTransition(fp, OriginAirport);

Call the function from within the for loop instead and your transition works fine:

for (i = 0; i <= n - 1; i++) {
  fp[i] = [destAirportObjects[i][1], destAirportObjects[i][2]];
    myTransition([fp[i]], OriginAirport);
}

If you choose this solution, you should update myTransition() to take a single set of coordinates to make the code easier to understand.

Alternatively , don't make any changes to the basemap.js file, but update myTransition so that the creation of the group (var g2) is completed within the destination for loop. Here's what you currently have in move.js starting at line 21:

var g2 = map_svg.append("g").attr("id", "fp");

// Creating the planes and flight paths programmatically.*************************************
for (i = 0; i < destPoi.length; i++) {
  //creating flight path data with line generator
  pathData[i] = lineGenerator([originPoint, t_dest_poi[i]]);
  //continue with loop

This is causing the g2 variable to be overwritten each time we move through the loop. There needs to be a distinct group created for each transition/path.

// Creating the planes and flight paths programmatically.*************************************
for (i = 0; i < destPoi.length; i++) {
  var g2 = map_svg.append("g").attr("class", "fp");
  //creating flight path data with line generator
  pathData[i] = lineGenerator([originPoint, t_dest_poi[i]]);
  //continue with loop

Finally, since there are multiple elements in this case, "fp" should be the class of var g2, not the ID. Remember to update your accessors accordingly.

Edit: Here's the sample for method #1 and method #2

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM