2013-07-22 14 views
5

Tôi đang sử dụng D3.js để tạo và hiển thị đường dẫn từ tệp GeoJSON. Điều đó hoạt động tốt, nhưng bây giờ tôi muốn tạo hiệu ứng cho một đối tượng dọc theo con đường đó. Tôi biết làm thế nào để làm điều đó bằng D3 và SVG tiêu chuẩn:Làm thế nào để animate một đối tượng dọc theo một đường dẫn GeoJSON sử dụng d3.js?

  1. Tạo một sự chuyển tiếp và thiết lập thời gian của nó
  2. Đối với mỗi khung hình của quá trình chuyển đổi, sử dụng% hoàn thành để tìm tọa độ dọc theo con đường
  3. Move đối tượng với các tọa độ được tìm thấy ở bước 2

Thật đơn giản. Nhưng vấn đề tôi gặp phải là d3.geo.path() dường như không trả về bất kỳ dữ liệu độ dài hoặc vị trí nào giống như đối tượng đường dẫn D3 chuẩn (chẳng hạn như phương thức getPointAtLength() hữu ích). Vì vậy, tôi không thể tìm thấy tọa độ x, y của một điểm tại, ví dụ: 25% dọc theo đường dẫn.

Có cách nào để lấy dữ liệu này không? (Hoặc có cách nào tốt hơn, chẳng hạn như chuyển d3.geo.path() sang đường dẫn D3 thông thường?)

Dưới đây là phiên bản rút gọn của mã của tôi; một ví dụ sống là ở đây: 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 +")"; 
    } 
}); 

Trả lời

8

Vâng, tôi figured it out, nhưng tôi không hoàn toàn chắc chắn nếu giải pháp của tôi là "đúng" cách để làm điều đó. Về cơ bản, tôi đã sử dụng D3 để chọn các phần tử SVG thô được tạo bởi đối tượng d3.geo.path().

Lưu ý các thay đổi đối với targetPath, pathNode, và pathLength biến, và cũng để các chức năng transform()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] + ")"; 
    } 
}); 

sống ví dụ là ở đây: http://jsfiddle.net/5m35J/6/