// see also: http://bl.ocks.org/dwtkns/4973620 var width = window.innerWidth; var height = window.innerHeight; const eu_countries = ['Austria', 'Italy', 'Belgium', 'Latvia', 'Bulgaria', 'Lithuania', 'Croatia', 'Luxembourg', 'Cyprus', 'Malta', 'Czechia', 'Netherlands', 'Denmark', 'Poland', 'Estonia ', 'Portugal', 'Finland ', 'Romania', 'France', 'Slovakia', 'Germany', 'Slovenia', 'Greece', 'Spain', 'Hungary', 'Sweden', 'Ireland']; const config = { 'max_y_rotation' : 55, } var graph = { nodes: [ { id: "New York", lat: 40.706109, lon: -74.01194 }, { id: "London", lat: 51.508070, lon: -0.126432 }, { id: "Montevideo", lat: -34.901776, lon: -56.163983 }, { id: "London-NewYork1" }, { id: "London-NewYork2" }, { id: "London-NewYork3" }, { id: "Montevideo-London" } ], links: [ { source: "New York", target: "London-NewYork1" }, { source: "New York", target: "London-NewYork2" }, { source: "New York", target: "London-NewYork3" }, { source: "London-NewYork1", target: "London" }, { source: "London-NewYork2", target: "London" }, { source: "London-NewYork3", target: "London" }, { source: "London", target: "Montevideo-London" }, { source: "Montevideo-London", target: "Montevideo" } ] } const force = d3.forceSimulation() .force("link", d3.forceLink() .id(function (d) { return d.id; }) .distance(10)) .force("charge", d3.forceManyBody().strength(-200)); const svg = d3.select("body") .append("svg") .attr("width", width) .attr("height", height); const container = svg.append("g").attr("id", "container"); const projection = d3.geoOrthographic() .center([0, 0]) .translate([width / 2, height / 2]) .rotate([ -12, -52, 0]) .clipAngle(90) .scale(height*1.5); const proj = d3.geoPath().projection(projection); const graticule = d3.geoGraticule10(); const g_countries = container.append("g").attr("id", "countries"); const g_borders = container.append("g").attr("id", "borders"); container.append("g") .append('path') .attr("class", "graticule") .attr('d', proj(graticule)) .attr("fill", "none") .attr("stroke-width", "!px") .attr("stroke", (n) => { return "lightgray"; }); ; d3.json("https://cdn.jsdelivr.net/npm/world-atlas@2/countries-110m.json").then(function (world) { // land = topojson.feature(world, world.objects.land) const borders = topojson.mesh(world, world.objects.countries, (a, b) => a !== b) console.log(borders); const countries = topojson.feature(world, world.objects.countries).features; // console.log(topojson.feature(world, world.objects.countries).features); g_countries.selectAll("path") .data(countries) .enter() .append("path") .attr("class", "countries") .attr("d", proj) .attr("fill", (n) => { if(eu_countries.indexOf(n.properties.name) !== -1) { return ''; } return "lightgray"; }); g_borders//.selectAll("path") // .data(borders) // .enter() .append("path") .attr("class", "borders") .attr("d", proj(borders)) .attr("fill", "none") .attr("stroke-width", "2px") .attr("stroke", (n) => { return "white"; }); const links = container.append('g') .attr("id", "links") .selectAll("line") .data(graph.links) .enter() .append("line") .attr("stroke-width", 2) .attr("stroke", "black"); const nodes = container.append('g') .attr("id", "nodes") .selectAll("circle") .data(graph.nodes) .enter() .append("circle") .attr('r', 5) .call(d3.drag() .on("start", dragInicia) .on("drag", dragging) .on("end", dragTermina)); force.nodes(graph.nodes); force.force("link").links(graph.links); graph.nodes.forEach(function (d) { if (d.lon && d.lat) { var p = projection([d.lon, d.lat]); d.fx = p[0]; d.fy = p[1]; } }) //simulaciĆ³n y actualizacion de la posicion de los nodos en cada "tick" force.on("tick", function () { links .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; }) ; nodes .attr('cx', function (d) { return d.x; }) .attr('cy', function (d) { return d.y; }) ; }) function dragInicia(d) { if (!d.lon || !d.lat) { if (!d3.event.active) force.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) force.alphaTarget(0); d.fx = null; d.fy = null; } } function refresh() { container.selectAll(".countries").attr("d", proj); container.selectAll(".graticule").attr("d", proj(graticule)); container.selectAll(".borders").attr("d", proj(borders)); // console.log(graph.nodes); force.alpha = 0; force.restart(); graph.nodes.forEach(function (d) { if (d.lon && d.lat) { var p = projection([d.lon, d.lat]); d.fx = p[0]; d.fy = p[1]; } }) } // svg.call(d3.zoom().extent([[0,0],[1,1]]).scaleExtent([0.3, 6]).on("start", function () { // // svg.node().classList.add("dragging"); // }).on("end", function () { // // svg.node().classList.remove("dragging"); // }).on("zoom", function ({ transform }) { // // container.attr("transform", transform); // o = [transform.x/6, -transform.y/6]; // o[1] = o[1] > config.max_y_rotation ? config.max_y_rotation : // o[1] < -config.max_y_rotation ? -config.max_y_rotation : // o[1]; // projection .rotate(o).scale(window.innerHeight*1.5*transform.k) // refresh(); // // container.attr("transform", "scale(" + transform.k + ")"); // })); // svg.on("wheel.zoom", (e) => { // }, {passive: false}) d3.geoZoom() .northUp(true) .projection(projection) .scaleExtent([.3, 6]) .onMove(refresh)(svg.node()); // (); // d3.select('svg').call(d3.drag() // .on("start", mousedown) // .on("drag", mousemove) // .on("end", mouseup)); // var m0, o0; // function mousedown(e) { // m0 = [d3.event.x, d3.event.y]; // o0 = projection.rotate(); // console.log(e, d3.event, m0,o0); // // d3.event.preventDefault(); // } // function mousemove() { // if (m0) { // var m1 = [d3.event.x, d3.event.y] // , o1 = [o0[0] + (m1[0] - m0[0]) / 6, o0[1] + (m0[1] - m1[1]) / 6]; // o1[1] = o1[1] > config.max_y_rotation ? config.max_y_rotation : // o1[1] < -config.max_y_rotation ? -config.max_y_rotation : // o1[1]; // projection.rotate(o1); // // sky.rotate(o1); // refresh(); // } // } // function mouseup() { // if (m0) { // mousemove(); // m0 = null; // } // } function resize(){ width = window.innerWidth; height = window.innerHeight; d3.selectAll('svg') .attr("width", width) .attr("height", height); projection.translate([width / 2, height / 2]); projection.scale(height*1.5); refresh(); } window.addEventListener('resize', resize); });