2013-08-10 31 views
17

Tôi đang cố tạo bản đồ của 10 cơ sở lớn của NASA trong D3. Tôi đã tạo thành công bản đồ cơ sở của Hoa Kỳ và gắn thêm logo của NASA tại mỗi vị trí trung tâm dựa trên một .csv với vĩ độ và kinh độ. Tuy nhiên, tôi không thể tìm ra cách thanh lịch nào để vẽ đường/liên kết/vòng cung/kết nối giữa các điểm trên bản đồ.Làm thế nào để vẽ một đường thẳng/liên kết giữa hai điểm trên bản đồ D3 dựa trên vĩ độ/kinh độ?

Trong đoạn mã dưới đây, tôi đã vẽ một đường thẳng giữa GSFC và KSC (sử dụng 'var = places', 'var = route', và 'svg.append ("path")') nhưng nó nằm trên một Lớp SVG, do đó, nó nằm trên đầu trang của các biểu tượng (trông có vẻ khủng khiếp) và không mở rộng (hoặc biến mất cũng sẽ tốt) khi nhấp vào để phóng to trên trạng thái. Tôi muốn có thể vẽ liên kết giữa các trung tâm dựa trên dữ liệu vĩ độ và kinh độ từ .csv.

<!DOCTYPE html> 
<meta charset="utf-8"> 
<style> 

.background { 
    fill: none; 
    pointer-events: all; 
} 

#states { 
    fill: #aaaaaa; 
} 

#states .active { 
    fill: #ff0000; 
    fill-opacity: .5; 
} 

#state-borders { 
    fill: none; 
    stroke: #ffffff; 
    stroke-width: 1.5px; 
    stroke-linejoin: round; 
    stroke-linecap: round; 
    pointer-events: none; 
} 

path.link { 
    fill: none; 
    stroke: #666666; 
    stroke-width: 1.5px; 
} 

.stroke { 
    fill: none; 
    stroke: #000; 
    stroke-width: 3px; 
} 

.fill { 
    fill: #fff; 
} 

.graticule { 
    fill: none; 
    stroke: #777; 
    stroke-width: .5px; 
    stroke-opacity: .5; 
} 

.route { 
    fill: none; 
    stroke: blue; 
    stroke-width: 3px; 
} 

</style> 
<body> 
    <h2> 
     <span>NASA Centers</span> 
    </h2> 

<script src="http://d3js.org/d3.v3.min.js"></script> 
<script src="http://d3js.org/d3.geo.projection.v0.min.js"></script> 
<script src="http://d3js.org/topojson.v1.min.js"></script> 
<script> 

var width = 1000, 
    height = 600, 
    centered; 

var projection = d3.geo.albersUsa() 
    .scale(1070) 
    .translate([width/2, height/2]); 

var path = d3.geo.path() 
    .projection(projection); 

var graticule = d3.geo.graticule(); 

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

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

var places = { 
    GSFC: [-76.852587, 38.991621], 
    KSC: [-80.650813, 28.524963] 
    }; 

var route = { 
    type: "LineString", 
    coordinates: [ 
    places.GSFC, 
    places.KSC 
    ] 
}; 

var point = svg.append("g") 
    .attr("class", "points") 
    .selectAll("g") 
    .data(d3.entries(places)) 
    .enter().append("g") 
    .attr("transform", function(d) { return "translate(" + projection(d.value) + ")"; }); 

point.append("text") 
    .attr("y", 5) 
    .attr("dx", "1em") 
    .text(function(d) { return d.key; }); 

d3.json("us.json", function(error, us) { 
    g.append("g") 
     .attr("id", "states") 
    .selectAll("path") 
     .data(topojson.feature(us, us.objects.states).features) 
    .enter().append("path") 
     .attr("d", path) 
     .on("click", clicked); 

    g.append("path") 
     .datum(topojson.mesh(us, us.objects.states, function(a, b) { return a !== b; })) 
     .attr("id", "state-borders") 
     .attr("d", path); 

    d3.csv("nasacenters.csv", function(error, data) { 
     g.selectAll("image").data([0]) 
      .data(data) 
      .enter() 
      .append("image") 
      .attr("xlink:href", "nasalogo.png") 
      .attr("width", "30") 
      .attr("height", "30") 
      .attr("x", function(d) { 
        return projection([d.lon, d.lat])[0]-15; 
      }) 
      .attr("y", function(d) { 
        return projection([d.lon, d.lat])[1]-15; 
      }) 

     svg.append("path") 
      .datum(route) 
      .attr("class", "route") 
      .attr("d", path) 
      .style("opacity", 0.5); 

    }); 

}); 

function clicked(d) { 
    var x, y, k; 

    if (d && centered !== d) { 
    var centroid = path.centroid(d); 
    x = centroid[0]; 
    y = centroid[1]; 
    k = 4; 
    centered = d; 
    } else { 
    x = width/2; 
    y = height/2; 
    k = 1; 
    centered = null; 
    } 

    g.selectAll("path") 
     .classed("active", centered && function(d) { return d === centered; }); 

    g.transition() 
     .duration(750) 
     .attr("transform", "translate(" + width/2 + "," + height/2 + ")scale(" + k + ")translate(" + -x + "," + -y + ")") 
     .style("stroke-width", 1.5/k + "px"); 
} 

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

Các tập tin .csv là theo định dạng sau:

code,center,lat,lon 
GSFC,Goddard Space Flight Center,38.991621,-76.852587 
KSC,Kennedy Space Center,28.524963,-80.650813 
JPL,Jet Propulsion Laboratory,34.200463,-118.176008 
DFRC,Dryden Flight Research Center,34.613714,-118.076790 
GRC,Glenn Research Center,41.415891,-81.861774 
MSFC,Marshall Space Flight Center,34.646554,-86.674368 
ARC,Ames Research Center,37.409574,-122.064292 
LaRC,Langley Research Center,37.092123,-76.376230 
JSC,Johnson Space Center,29.551508,-95.092256 
SSC,Stennis Space Center,30.363692,-89.600036 

Trả lời

25

tôi sửa đổi ví dụ của bạn hơi dựa trên những vấn đề bạn mô tả: http://bl.ocks.org/erikhazzard/6201948

Dường như có ba vấn đề:

  1. Đường dẫn vẽ trên đầu biểu tượng. Để khắc phục điều này, bạn có thể thay đổi thứ tự khi bạn thêm các mục vào nhóm hoặc thêm các nhóm phụ vào nhóm g chính của bạn, đảm bảo thứ tự mà bạn thêm các nhóm khớp với thứ tự bạn muốn mọi thứ xuất hiện.

  2. Đường dẫn giữa các điểm không phóng to khi bạn phóng to bản đồ. Để khắc phục điều này, hãy đảm bảo thêm mọi thứ vào nhóm mà bạn đang sửa đổi hàm đã nhấp(). Trong trường hợp này, nhóm g của bạn đang được thu phóng, vì vậy, nếu bạn thêm đường dẫn vào nhóm g thay vì trực tiếp các đường dẫn cũng sẽ thu phóng đường dẫn svg. Trong ví dụ được cung cấp, văn bản cũng không phóng to - đó là vì nó được thêm trực tiếp vào SVG chứ không phải nhóm g đang được chuyển đổi.

  3. Đường dẫn không được tạo tự động từ dữ liệu. Để khắc phục điều này, bạn có thể tạo một mảng chứa các đối tượng LineString từ dữ liệu. Ví dụ:

    for(var i=0, len=data.length-1; i<len; i++){ 
        // (note: loop until length - 1 since we're getting the next 
        // item with i+1) 
         links.push({ 
          type: "LineString", 
          coordinates: [ 
           [ data[i].lon, data[i].lat ], 
           [ data[i+1].lon, data[i+1].lat ] 
          ] 
         }); 
        } 
    

    Sau đó, làm mẫu tham gia dữ liệu chuẩn và chuyển vào danh sách links. Khi bạn vượt qua trong path như thuộc tính d, nó sẽ tạo ra một vòng cung lớn dựa trên các tọa độ cho từng hạng mục:

    // Standard enter/update 
    var pathArcs = arcGroup.selectAll(".arc") 
        .data(links); 
    
    //enter 
    pathArcs.enter() 
        .append("path").attr({ 
         'class': 'arc' 
        }).style({ 
         fill: 'none', 
        }); 
    
    //update 
    pathArcs.attr({ 
         //d is the points attribute for this path, we'll draw 
         // an arc between the points using the arc function 
         d: path 
        }) 
        .style({ 
         stroke: '#0000ff', 
         'stroke-width': '2px' 
        }) 
    

Trong ví dụ của tôi (http://bl.ocks.org/enoex/6201948) tôi đã thêm một sự chuyển tiếp trên những con đường vòng cung tuyệt vời để minh họa cách đường dẫn được vẽ dựa trên thứ tự các cặp tọa độ được truyền vào đối tượng liên kết.

Hy vọng điều đó sẽ hữu ích!

+0

Điều đó hoàn toàn tuyệt vời. Cảm ơn bạn! Nghiêm túc, không thể cảm ơn đủ. Nó không chỉ giải quyết vấn đề cho tôi, mà ý kiến ​​của bạn là rất nhiều thông tin và sẽ giúp tôi tìm hiểu cách khắc phục những vấn đề này trong tương lai. – Lokitez

+0

Hiện ... imageGroup.exit(). Remove() ... không hoạt động khi được bao gồm bên trong ... chức năng được nhấp (d) ...? – Lokitez

+0

bạn có thể cần phải gọi exit() trên đối tượng lựa chọn ... ví dụ: var pathArcs = arcGroup.selectAll (". Arc") .data (liên kết); ... đường dẫnArcs.exit(). Remove(); – ErikHazzard

Các vấn đề liên quan