diff --git a/flaskr/static/js/plots/travel-legs-worldmap.js b/flaskr/static/js/plots/travel-legs-worldmap.js
new file mode 100644
index 0000000..a16be2d
--- /dev/null
+++ b/flaskr/static/js/plots/travel-legs-worldmap.js
@@ -0,0 +1,93 @@
+/**
+ * Draws a SVG in the DOM element identified by `containerSelector`.
+ *
+ * Issues
+ * ------
+ *
+ * - No Zoom (spent 4h on this already)
+ * - No animations (wait 'til it's polished)
+ *
+ * @param containerSelector string
+ *   CSS selector, like "#d3viz"
+ * @param worldDataUrl
+ *   A JSON file with reusable world data.
+ *   @see /static/public/data/world-earth.geojson
+ * @param travelsDataUrl
+ *   A CSV file with rows of
+ *   - origin_lon
+ *   - origin_lat
+ *   - destination_lon
+ *   - destination_lat
+ */
+function draw_travel_legs_worldmap(containerSelector, worldDataUrl, travelsDataUrl) {
+
+    document.addEventListener('DOMContentLoaded', () => {
+        const margin = {top: 0, right: 0, bottom: 0, left: 0};
+        // var width = $(containerSelector).parent().width();
+        // var height = width - margin.top - margin.bottom;
+        // let width = width - margin.left - margin.right;
+        //{#var height = Math.max(300, 600) - margin.top - margin.bottom;#}
+        //{#var width = Math.max(880, $(containerSelector).parent().width());#}
+
+        const size_ratio = 0.85;
+        let width = 629.0 * size_ratio;
+        let height = 604.0 * size_ratio;
+        //{#width = 500.0;#}
+        //{#height = 400.0;#}
+
+        let offset_x = 0.0;
+        let offset_y = 0.0;
+
+        const svg = d3.select(containerSelector)
+            .append("svg")
+            .attr("width", width + margin.left + margin.right)
+            .attr("height", height + margin.top + margin.bottom);
+
+        const projection = d3.geoMercator()
+            .scale(85)
+            .translate([width / 2.0 + offset_x, height / 2.0 + offset_y]);
+
+        const geopath = d3.geoPath().projection(projection);
+
+        function draw_from_data(worldData, legsData) {
+            const link = [];
+            legsData.forEach(function (row) {
+                source = [+row.origin_lon, +row.origin_lat];
+                target = [+row.destination_lon, +row.destination_lat];
+                topush = {type: "LineString", coordinates: [source, target]};
+                link.push(topush);
+            });
+
+            svg.append("g")
+                .selectAll("path")
+                .data(worldData.features)
+                .enter()
+                .append("path")
+                .attr("fill", "#b8b8b8")
+                .attr("d", geopath)
+                .style("stroke", "#fff")
+                .style("stroke-width", 0);
+
+            svg.selectAll("myPath")
+                .data(link)
+                .enter()
+                .append("path")
+                .attr("d", geopath)
+                //            .attr("d", function (d) {
+                //                return geopath(d);
+                //            })
+                .style("fill", "none")
+                .style("stroke", "#69b3a2")
+                .style("stroke-width", 2);
+
+        }
+
+        const worldDataPromise = d3.json(worldDataUrl);
+        const travelsDataPromise = d3.csv(travelsDataUrl);
+        Promise.all([worldDataPromise, travelsDataPromise]).then((values) => {
+            draw_from_data(values[0], values[1]);
+        });
+
+    });
+
+}
\ No newline at end of file
--
libgit2 0.21.2