I'm trying to place a force layout node system on a map. SOME of the nodes have lon and lat values in the json file I'm using. Other nodes only need to be connected but not georeferenced. I would like to place in position the nodes which have lon and lat values and the others simply to be connected.
(I found this example which I followed but the nodes without lon and lat values are placed outside the svg: https://bl.ocks.org/cmgiven/4cfa1a95f9b952622280a90138842b79) I also tried to filter the nodes with lon and lat values but still no luck.
This is what I'm getting currently:
Here's my code:
var w = 1340;
var h = 620;
//Zoom del mapa porque panamá es muy peque en la aproyección
var zoomOffset = 75000;
var wOffset = 103300;
var hOffset = 11500;
var escala = 0.50;
//Tipo de proyección del mapa escalado y transladado
//posicion del mapa
var projection = d3.geoMercator()
.translate([w + wOffset, h + hOffset])
.scale([zoomOffset])
;
//Los paths que toman el tipo de proyección
var path = d3.geoPath().projection(projection);
//El "centro" del pais
var center = projection([9.018, -79.500])
;
//Esquema de colores
var color = d3.scaleOrdinal(d3.schemeCategory20);
//Define la siulación de fuerza
var fuerza = d3.forceSimulation()
.force("link", d3.forceLink()
.id(function(d){
return d.id;
})
.distance(40))
.force("charge", d3.forceManyBody().strength(-5))
.force("center", d3.forceCenter(w/2, h/2))
;
//Leer datos de ambos json y llamar la funcion que dibuja todo
d3.queue()
.defer(d3.json, 'proyectos_v5.json')
.defer(d3.json, 'panama.json')
.awaitAll(dibujar)
;
//Leer los datos y dibujar los assets y el mapa
function dibujar (error, data){
if (error) {throw error}
//Leer los datos de los json y ponerlos en arreglos distintos
var graph = data[0];
var features = data[1].features;
//Printea los datos para verificar
console.log(graph);
console.log(features);
//Le dice a la simulación cuales son los nodos y los links
fuerza.nodes(graph.nodes);
fuerza.force("link").links(graph.edges);
//svg en donde dibujar
var svg = d3.selectAll("body")
.append("svg")
.attr('width', w)
.attr('height', h)
;
//grupo en donde esten todos los objetos draggeables
var mapa = svg.append("g")
.attr('id', "mapa") //para luego dibujar los circulos y el mapa
//dibuja el mapa, sin zoom porque no se necesita
.selectAll("path")
.data(features)
.enter()
.append("path")
.attr("d", path)
.style('fill', "#EDEDED")
;
//crea las lineas con un svg y los datos de "edges"
var lineas = svg.append('g')
.selectAll("line")
.data(graph.edges)
.enter()
.append("line")
.style("stroke", "black")
.style('stroke-width', 1)
;
//crea los nodos de acuerdo a los nombres
var nodos = svg.append('g')
.selectAll("circle")
.data(graph.nodes)
.enter()
.append("circle")
.style('fill', function(d, i){
return color(i);
})
.attr('r',5 )
.call(d3.drag()
.on("start", dragInicia)
.on("drag", dragging)
.on("end", dragTermina)) //llama la el metodo de nodos dragg y le dice que hacer en cada momento
;
nodos.append("title")
.text(function(d){
return d.id;
});
//simulación y actualizacion de la posicion de los nodos en cada "tick"
fuerza.on("tick", function (){
lineas
.attr('x1', function(d){
return d.source.x;
})
.attr('y1', function(d){
return d.source.y;
})
.attr('x2', function(d){
return d.target.x;
})
.attr('y2', function(d){
return d.target.y;
})
;
nodos
.attr('cx', function(d){
if(d.fixed== true"){
return projection([d.lon, d.lat])[0];
} else {
return d.x;
}
})
.attr('cy', function(d){
if(d.fixed== "true"){
return projection([d.lon, d.lat])[1];
} else {
return d.y;
}
})
;
})
//crea las funciones para saber qué hacer en cada momento del dragging
function dragInicia(d){
if (!d3.event.active) fuerza.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
}
function dragging(d){
d.fx = d3.event.x;
d.fy = d3.event.y;
}
function dragTermina(d){
if(!d3.event.active) fuerza.alphaTarget(0);
d.fx = null;
d.fy = null;
}
};
and some of the json:
{
"id": "Urbanicación La Marina",
"lat": 9.0463,
"lon": -79.4204,
"año": 2019,
"tipo": "proyecto",
"area": "urbano",
"extension": "",
"estado": "",
"publico": "",
"fixed": "true"
},
{
"id": "Zona Logística del aeropuerto de Tocumen",
"lat": 9.0567,
"lon": -79.4191,
"año": 2019,
"tipo": "proyecto",
"area": "urbano",
"extension": "",
"estado": "",
"publico": "",
"fixed": "true"
},
{
"id": "100 ciudades resilentes",
"lat": "",
"lon": "",
"año": "",
"tipo": "actor",
"area": "",
"extension": "",
"estado": "",
"publico": "",
"fixed": "false"
},
{
"id": "ACOBIR",
"lat": "",
"lon": "",
"año": "",
"tipo": "actor",
"area": "",
"extension": "",
"estado": "",
"publico": "",
"fixed": "false"
}