2013-08-10 3 views
17

Ich versuche eine Karte der 10 wichtigsten NASA-Einrichtungen in D3 zu erstellen. Ich habe erfolgreich die Basis-Karte der Vereinigten Staaten und angehängte NASA-Logos an jedem der zentralen Orte basierend auf einer .csv mit Längen- und Breitengrad erstellt. Ich kann jedoch keine elegante Methode zum Zeichnen von Linien/Verbindungen/Bögen/Verbindungen zwischen den Punkten auf der Karte finden.Wie zeichne ich eine Linie/Verbindung zwischen zwei Punkten auf einer D3-Karte basierend auf dem Längen-/Breitengrad?

Im folgenden Code habe ich eine Linie zwischen GSFC und KSC (mit den 'var = Orte', 'var = Route' und 'svg.append ("Pfad")) gezeichnet, aber es ist auf einem SVG-Ebene, also ist es auf der Oberseite der Logos (die schrecklich aussieht) und nicht skalieren (oder gehen weg, wäre auch in Ordnung), wenn Sie klicken, um einen Zustand zu vergrößern. Ich möchte in der Lage sein, Verbindungen zwischen den Zentren basierend auf den Breiten- und Längengraddaten aus der .csv zu ziehen.

<!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> 

Die CSV-Datei ist in folgendem Format:

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 

Antwort

25

ich dein Beispiel leicht modifiziert auf der Grundlage der Probleme, die Sie beschrieben: http://bl.ocks.org/erikhazzard/6201948

Es sieht aus wie es gibt drei Probleme:

  1. Pfade zeichnen über Symbol. Um dies zu beheben, können Sie die Reihenfolge beim Hinzufügen von Elementen zur Gruppe ändern oder Untergruppen zu Ihrer Hauptgruppe g hinzufügen, um sicherzustellen, dass die Reihenfolge, in der Sie die Gruppen hinzufügen, der Reihenfolge entspricht, in der die Objekte angezeigt werden sollen.

  2. Die Pfade zwischen den Punkten werden nicht vergrößert, wenn Sie die Karte zoomen. Um dies zu beheben, stellen Sie sicher, dass Sie der Gruppe, in der Sie die clicked() -Funktion ändern, alles hinzufügen. In diesem Fall wird Ihre g-Gruppe vergrößert. Wenn Sie also die Pfade zur g-Gruppe anstatt der svg direkt hinzufügen, werden die Pfade ebenfalls vergrößert. Im vorliegenden Beispiel wird der Text auch nicht vergrößert, da er direkt der SVG hinzugefügt wird und nicht der Gruppe g, die transformiert wird.

  3. Pfade werden nicht automatisch aus den Daten erstellt. Um dies zu beheben, können Sie ein Array mit LineString-Objekten aus den Daten generieren. Zum Beispiel

    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 ] 
          ] 
         }); 
        } 
    

    Dann tut die Standard-Datenmuster verbinden und in der links Liste mit den Daten übergeben. Wenn Sie in path als d Attribut übergeben, wird es einen großen Bogen erzeugt auf der Basis der Koordinaten für jedes Element:

    // 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' 
        }) 
    

In meinem Beispiel (http://bl.ocks.org/enoex/6201948) ich einen Übergang auf den großen Bogen Pfade hinzugefügt veranschaulichen, wie der Pfad basierend auf der Reihenfolge der Koordinatenpaare gezeichnet wird, die in das Verknüpfungsobjekt übergeben werden.

Hoffe, dass hilft!

+0

Das ist absolut brillant. Vielen Dank! Ernsthaft, ich kann dir nicht genug danken. Es hat nicht nur das Problem für mich gelöst, sondern Ihre Kommentare sind sehr informativ und werden mir helfen zu lernen, wie Sie diese Probleme in Zukunft beheben können. – Lokitez

+0

Funktioniert ... imageGroup.exit(). Remove() ... funktioniert nicht, wenn in ... function geklickt (d) ...? – Lokitez

+0

müssen Sie möglicherweise exit() für das Auswahlobjekt aufrufen ... z. B. var pathArcs = arcGroup.selectAll (". Arc") .data (Verknüpfungen); ... pathArcs.exit(). Remove(); – ErikHazzard

Verwandte Themen