tooltips force directed chart bubble bar d3.js maps

d3.js - force - ¿Cómo dibujar una línea/enlace entre dos puntos en un mapa D3 en función de la latitud/longitud?



d3 tooltip onmouseover (1)

Estoy intentando crear un mapa de las 10 instalaciones principales de la NASA en D3. He generado con éxito el mapa base de los Estados Unidos y adjuntado los logotipos de la NASA en cada una de las ubicaciones del centro en función de un .csv con latitud y longitud. Sin embargo, no puedo encontrar una manera elegante de dibujar líneas / enlaces / arcos / conexiones entre los puntos en el mapa.

En el código a continuación, dibujé una línea entre GSFC y KSC (usando ''var = lugares'', ''var = ruta'' y ''svg.append ("ruta")'') pero está en una capa SVG, así que se encuentra en la parte superior de los logotipos (que se ve horrible) y no se puede escalar (o desaparecería también estaría bien) al hacer clic para ampliar un estado. Me gustaría poder dibujar enlaces entre los centros basados ​​en los datos de latitud y longitud de .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>

El archivo .csv está en el siguiente formato:

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


Modifiqué tu ejemplo ligeramente según los problemas que describiste: http://bl.ocks.org/erikhazzard/6201948

Parece que hay tres problemas:

  1. Trayectorias dibujan sobre el icono . Para solucionar este problema, puede cambiar el orden de cuando agrega elementos al grupo o agregar subgrupos a su grupo g principal, asegurándose de que el orden en que agregue los grupos coincida con el orden en que desea que aparezcan las cosas.

  2. Las rutas entre los puntos no hacen zoom cuando se acerca el mapa . Para solucionar este problema, asegúrese de agregar todo al grupo que está modificando la función de clic (). En este caso, su grupo g se está ampliando, así que si agrega las rutas al grupo g lugar de a la svg directamente, las rutas también se acercarán. En el ejemplo proporcionado, el texto tampoco se acerca, porque se agrega directamente al SVG y no al grupo g que se está transformando.

  3. Las rutas no se crean automáticamente a partir de los datos . Para solucionar esto, puede generar una matriz que contenga objetos LineString a partir de los datos. Por ejemplo,

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

    Luego, haga el patrón de unión de datos estándar y pase la lista de links a los datos. Cuando pasa en path como el atributo d , generará un gran arco basado en las coordenadas para cada elemento:

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

En mi ejemplo ( http://bl.ocks.org/enoex/6201948 ) agregué una transición en las grandes rutas de arco para ilustrar cómo se dibuja la ruta según el orden de los pares de coordenadas pasados ​​al objeto de enlaces.

¡Espero que ayude!