From b520f66caa58403dbdb100d4274b1282e74ed21c Mon Sep 17 00:00:00 2001 From: Ruben van de Ven Date: Mon, 29 Mar 2021 20:49:50 +0200 Subject: [PATCH] WIP --- wiki_relations.py | 6 + www/graph.js | 287 ++++++++++++++++++++++++++++++++++++++++ www/index.html | 309 ++++++++++++++++++++++++++++++++++++++++++++ www/world_test.html | 309 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 911 insertions(+) create mode 100644 www/graph.js create mode 100644 www/index.html create mode 100644 www/world_test.html diff --git a/wiki_relations.py b/wiki_relations.py index abd09ed..8557676 100644 --- a/wiki_relations.py +++ b/wiki_relations.py @@ -194,6 +194,7 @@ def addDataitemToCollection(subjectId, prop, data, collection): collection['nodes'][subjectId][prop] = [] collection['nodes'][subjectId][prop].append(json.dumps(data)) else: + # TODO: map as properties on link! if data['item'] not in collection['nodes']: collection['nodes'][data['item']] = getObjForSubject(data['item']) collection['links'].append({ @@ -201,6 +202,11 @@ def addDataitemToCollection(subjectId, prop, data, collection): 'target': data['item'], 'name': prop }) + elif data['type'] == 7: + # Geolocation + lat, lon = data['item'].split(',') + collection['nodes'][subjectId]['lat'] = lat + collection['nodes'][subjectId]['lon'] = lon else: logger.error(f"Unknown type: {data['type']}: {prop} : {data}") diff --git a/www/graph.js b/www/graph.js new file mode 100644 index 0000000..69ddea7 --- /dev/null +++ b/www/graph.js @@ -0,0 +1,287 @@ +// 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); +}); + + diff --git a/www/index.html b/www/index.html new file mode 100644 index 0000000..feb9543 --- /dev/null +++ b/www/index.html @@ -0,0 +1,309 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/www/world_test.html b/www/world_test.html new file mode 100644 index 0000000..feb9543 --- /dev/null +++ b/www/world_test.html @@ -0,0 +1,309 @@ + + + + + + + + + + + + + + + \ No newline at end of file