//Width y height var w = 1340; var h = 620; //Zoom del mapa porque panamá es muy peque en la aproyección var zoomOffset = 112000; var wOffset = 154700; var hOffset = 17300; var escala = 0.50; var radio = 4; var opacidad_inicial = 1; //Here I set up the leaflet map var map = L.map('map').setView([8.952999, -79.53406], 13); mapLink = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map); //Once leaflet is set up I create a SVG to use with D3.js and add it to the map var svgLayer = L.svg(); svgLayer.addTo(map); //svg en donde dibujar var svg = d3.select("#map") .select("svg"); var g = svg.select('g'); //Define la siulación de fuerza var fuerza = d3.forceSimulation() //fuerza atractora hacia el centro de los nodos que no están conectados .force("x", d3.forceX(w / 2).strength(.3)) .force("y", d3.forceY(h / 2).strength(.3)) //link con el id del json .force("link", d3.forceLink() .id(function(d){ return d.id; }) //distancia de los links .distance(50)) //fuerza entre los nodos .force("charge", d3.forceManyBody().strength(-150)) ; //Leer datos de ambos json y llamar la funcion que dibuja todo d3.json('proyectos_v8.json', function(data){ //Leer los datos de los json y ponerlos en arreglos distintos var graph = data; //Printea los datos para verificar console.log(graph); //crea las lineas con un svg y los datos de "edges" var lineas = g.selectAll("line") .data(graph.edges) .enter() .append("line") .attr('class', "link") ; //crea los nodos de acuerdo a los nombres var nodos = g.selectAll("circle") .data(graph.nodes) .enter() .append("circle") //dependiendo del tipo o el area le da una clase del CSS .attr('class', function(d){ if (d.area == "urbano" || d.area == "ambiental" || d.area == "inclusion"){ return "nodos " + d.area; } if (d.tipo == "actor" || d.tipo == "colaborador" || d.tipo == "financiador"){ return "nodos " + d.tipo; } }) //dependiendo del tipo se le da un borde .style('stroke', function(d){ var borde = ""; if (d.tipo == "proyecto"){ borde = "#000000"; } if (d.tipo == "plan"){ borde = "#585858"; } if (d.tipo == "programa"){ borde = "#C0C0C0"; } return borde; }) .attr('stroke-width', 2) .attr('r',5 ) //si se click se muestran las conexiones .on("click", connectedNodes) //llama la el metodo de nodos dragg y le dice que hacer en cada momento .call(d3.drag() .on("start", dragInicia) .on("drag", dragging) .on("end", dragTermina) ) ; //filtra los nodos por actor para colocarles una opacidad inicial de 0... nodos .filter(function(d){ return d.tipo == "actor" || d.tipo == "colaborador" || d.tipo == "financiador" ; }) .attr('opacity', 0) ; //le dice a la simulacion cuales son los nodos y los links fuerza.nodes(graph.nodes); fuerza.force("link").links(graph.edges); //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; }) ; //pinta los nodos dentro del radio y el W y Y nodos .attr("cx", function(d) { return d.x = Math.max(radio, Math.min(w - radio, d.x)); }) .attr("cy", function(d) { return d.y = Math.max(radio, Math.min(h - radio, d.y)); }) .attr('r', function(d){ if(d.tipo == "actor"){ d.weight = lineas.filter(function(l) { return l.source.index == d.index || l.target.index == d.index }) .size(); var minRadius = 5; return minRadius + (d.weight ); }else { return 5; } }) ; }); //si tiene lon y lat clavelos al punto en el mapa //gracias a Andrew Reid (user:7106086 en stackoverflow) graph.nodes.forEach(function(d) { if(d.lon && d.lat) { p = new L.LatLng(d.lat, d.lon); console.log(p); d.fx = p[0]; d.fy = p[1]; } }) //saber si las conexiones se ven o no var toggle = 0; //Create an array logging what is connected to what var linkedByIndex = {}; for (i = 0; i < graph.nodes.length; i++) { linkedByIndex[i + "," + i] = 1; }; graph.edges.forEach(function (d) { linkedByIndex[d.source.index + "," + d.target.index] = 1; }); //This function looks up whether a pair are neighbours function neighboring(a, b) { return linkedByIndex[a.index + "," + b.index]; } function connectedNodes() { if (toggle == 0) { //Reduce the opacity of all but the neighbouring nodes d = d3.select(this).node().__data__; nodos .transition() .style("opacity", function (o) { return neighboring(d, o) | neighboring(o, d) ? 1 : 0; }) ; lineas .transition() .style("opacity", function (o) { return d.index==o.source.index | d.index==o.target.index ? 0.5 : 0; }) ; //Reduce the opacity toggle = 1; }else { //vuelve a poner la opacidad en 1 de los proyectos y 0.1 de los actores, etc nodos .filter(function(d){ return d.tipo == "proyecto" || d.tipo == "programa" || d.tipo == "plan"; }) .transition() .style("opacity", 1) ; nodos .filter(function(d){ return d.tipo == "actor" || d.tipo == "colaborador" || d.tipo == "financiador" ; }) .transition() .style("opacity", 0) ; // y las lineas a 0 lineas .transition() .style("opacity", 0) ; toggle = 0; } } //crea las funciones para saber qué hacer en cada momento del dragging // si tiene lon y lat dejelos donde están, los demas si se pueden draggear function dragInicia(d){ if (!d.lon || !d.lat) { if (!d3.event.active) fuerza.alphaTarget(0.3).restart(); d.fx = d.x; d.fy = d.y; } } function dragging(d){ if (!d.lon || !d.lat) { d.fx = d3.event.x; d.fy = d3.event.y; } } function dragTermina(d){ if (!d.lon ||!d.lat) { if(!d3.event.active) fuerza.alphaTarget(0); d.fx = null; d.fy = null; } } //Function which sets the transformation attribute to move the circles to the correct location on the map function drawAndUpdateCircles() { nodos.attr("transform", function(d) { if(d.lon && d.lat) { var p = new L.LatLng(d.lat, d.lon); console.log(p); d.fx = p[0]; d.fy = p[1]; } }) } //Finally set up the initial circles and bind the update drawAndUpdateCircles(); map.on("moveend", drawAndUpdateCircles); });