2013-07-22 9 views
5

Używam D3.js do generowania i renderowania ścieżki z pliku GeoJSON. To działa dobrze, ale teraz chciałbym animować obiekt wzdłuż tej ścieżki. Wiem jak to zrobić za pomocą D3 i standard SVG:Jak animować obiekt wzdłuż ścieżki GeoJSON za pomocą d3.js?

  1. Tworzenie przejścia i ustawić jej trwania
  2. Dla każdej klatki przejścia, użyj% kompletny znaleźć współrzędne wzdłuż ścieżki
  3. Move obiekt do współrzędnych znalezionych w kroku 2

To proste. Ale problem, który mam, polega na tym, że d3.geo.path() wydaje się nie zwracać żadnych długości ani danych pozycji, takich jak standardowy obiekt ścieżki D3 (na przykład pomocna metoda getPointAtLength()). Nie mogę znaleźć współrzędnych x, y punktu na, powiedzmy, 25% wzdłuż ścieżki.

Czy istnieje sposób na uzyskanie tych danych? (Czy jest lepszy sposób, na przykład konwersja d3.geo.path() do zwykłej ścieżki D3?)

Poniżej znajduje się skrócona wersja mojego kodu; na żywo przykładem jest tutaj: http://jsfiddle.net/5m35J/4/

json = { 
    ... // snipped for brevity 
}; 

// Draw a GeoJSON line on the map: 

map = $('#map'); 
xy = d3.geo.mercator().scale(480000).translate([630700, 401100]); 
path = d3.geo.path().projection(xy); 

vis = d3.select("#map") 
    .append("svg:svg") 
    .attr("width", 960) 
    .attr("height", 600); 

vis.append("svg:g") 
    .attr("class", "route") 
    .selectAll("path") 
    .data(json.features) 
    .enter() 
    .append("svg:path") 
    .attr("d", path) 
    .attr("fill-opacity", 0.5) 
    .attr("fill", "#fff") 
    .attr("stroke", "#333"); 

// Draw a red circle on the map: 

//len = 100; // how do I find the length of the path? 
origin_x = 100; 
origin_y = 100; 

group = vis.append("svg:g"); 

circle = group.append("circle") 
    .attr({ 
    r: 10, 
    fill: '#f33', 
    transform: function() { 
     //var p = path.getPointAtLength(0) 
     //return "translate(" + [p.x, p.y] + ")"; 
     return "translate("+ origin_x +","+ origin_y +")"; 
    } 
}); 

// Animate the circle: 

duration = 5000; 
circle.transition() 
    .duration(duration) 
    .ease("linear") 
    .attrTween("transform", function (d, i) { 
    return function (t) { 
     //var p = path.node().getPointAtLength(len*t) // d3.geo.path() doesn't provide a getPointAtLength() method! 
     //return "translate("+[p.x,p.y]+")" 
     var current_x = origin_x + origin_x * t; 
     var current_y = origin_y + origin_y * t;    
     return "translate("+ current_x +","+ current_y +")"; 
    } 
}); 

Odpowiedz

8

Cóż, zorientowaliśmy się, ale nie jestem całkowicie pewien, czy moje rozwiązanie jest „prawo” sposób to zrobić. Zasadniczo użyłem D3, aby wybrać surowe elementy SVG, które zostały utworzone przez obiekt d3.geo.path().

Uwaga zmiany do targetPath, pathNode i pathLength zmienne, a także funkcji transform() i attrTween():

// Draw a red circle on the map: 

group = vis.append("svg:g"); 

var targetPath = d3.selectAll('.route')[0][0], 
    pathNode = d3.select(targetPath).selectAll('path').node(), 
    pathLength = pathNode.getTotalLength(); 

circle = group.append("circle") 
    .attr({ 
    r: 10, 
    fill: '#f33', 
    transform: function() { 
     var p = pathNode.getPointAtLength(0) 
     return "translate(" + [p.x, p.y] + ")"; 
    } 
}); 

// Animate the circle: 

duration = 10000; 
circle.transition() 
    .duration(duration) 
    .ease("linear") 
    .attrTween("transform", function (d, i) { 
    return function (t) { 
     var p = pathNode.getPointAtLength(pathLength*t); 
     return "translate(" + [p.x, p.y] + ")"; 
    } 
}); 

żywo przykładem jest tutaj: http://jsfiddle.net/5m35J/6/

Powiązane problemy