Skip to content

Instantly share code, notes, and snippets.

@dhoboy
Last active August 29, 2015 14:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dhoboy/7e1dfa5ed8ebebef8dfe to your computer and use it in GitHub Desktop.
Save dhoboy/7e1dfa5ed8ebebef8dfe to your computer and use it in GitHub Desktop.
Jody's Journey: final map
Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
<!DOCTYPE html>
<meta charset="utf-8">
<style>
/* map styles */
.country { fill: #B8B8B8; }
.interior-boundary {
fill: none;
stroke: #FFFFFF;
stroke-dasharray: 2,2;
stroke-linejoin: round;
}
.place, .place-label { fill: #444; }
text {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 10px;
font-weight: bold;
}
.route {
fill: none;
stroke: red;
stroke-width: 3px;
stroke-linecap: round;
stroke-opacity: .8;
}
/* title and legend styles */
.legend {
position: relative;
margin: 0px 10px 80px 10px;
}
.key {
position: absolute;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 12px;
font-weight: bold;
margin: 0px 15px 0px 0px;
}
.Kolkata { left: 30px; }
.Darjeeling { left: 160px; }
.Nepal { left: 305px; }
.Myanmar { left: 425px; }
.Cambodia { left: 570px; }
.Laos { left: 725px; }
.Xishuangbanna { left: 850px; }
.Anhui { left: 30px; }
.Fujian { left: 160px; }
.Wuyi { left: 290px; }
.Qingdao { left: 390px; }
.Lishan { left: 515px; }
.Nantou { left: 640px; }
.Alishan { left: 775px; }
.Taiwan { left: 905px; }
.Shizuoka { left: 30px; }
.Uji { left: 180px; }
.Kyoto { left: 260px; }
.credit { left: 940px; top: 40px; font-size: 10px;}
</style>
<body>
<script src="http://d3js.org/d3.v3.js"></script>
<script src="http://d3js.org/d3.geo.projection.v0.min.js"></script>
<script src="http://d3js.org/topojson.v1.js"></script>
<script>
var width = 1000,
height = 590,
margin = { top: 40, left: 30, right: 150, bottom: 50 };
// draw svg
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
// map projection
var projection = d3.geo.patterson()
.center([58,54])
.scale(520)
.translate([0,0])
.precision(.1);
// path generator
var path = d3.geo.path()
.projection(projection)
.pointRadius(3);
// coordinates are added to this when constructRoute is called
var journey = [
{name:"Kolkata", dates:"Feb. 17-22"},
{name:"Darjeeling", dates:"Feb. 23-28"},
{name:"Nepal", dates:"March 1-6"},
{name:"Myanmar", dates:"March 7-10"},
{name:"Cambodia", dates:"March 11-13"},
{name:"Laos", dates:"March 14-18"},
{name:"Xishuangbanna", dates:"March 18-21"},
{name:"Anhui", dates:"March 22-28"},
{name:"Fujian", dates:"March 29-31"},
{name:"Wuyi", dates:"April 1-6"},
{name:"Qingdao", dates:"April 6-10"},
{name:"Lishan", dates:"April 11-14"},
{name:"Nantou", dates:"April 15-18"},
{name:"Alishan", dates:"April 18-20"},
{name:"Taiwan", dates:"April 21-26"},
{name:"Shizuoka", dates:"April 27-May 1"},
{name:"Uji", dates:"May 2-4"},
{name:"Kyoto", dest: "18", dates:"May 4-8"}
];
d3.json("asia.json", function(error, asia) {
var subunits = topojson.feature(asia, asia.objects.subunits),
places = topojson.feature(asia, asia.objects.places),
route = constructRoute(journey, places.features);
// draw the map
svg.selectAll(".subunit")
.data(subunits.features)
.enter()
.append("path")
.attr("class", function(d) { return "country"; })
.attr("d", path);
// draw interior boundaries between countries
svg.append("path")
.datum(topojson.mesh(asia, asia.objects.subunits, function(a, b) {
return a !== b;
}))
.attr("d", path)
.attr("class", "interior-boundary");
// draw curved paths between places
svg.selectAll(".route")
.data(route.coordinates)
.enter()
.append("path")
.attr("class", "route")
.attr("d", function(d) {
var source = projection(d[0]);
var target = projection(d[1]);
var dx = target[0] - source[0],
dy = target[1] - source[1],
dr = Math.sqrt(dx * dx + dy * dy);
return "M" + source[0] + "," + source[1] + "A" + dr + "," + dr + " 0 0,1 " + target[0] + "," + target[1];
});
// draw places on map
svg.append("path")
.datum(places)
.attr("d", path)
.attr("class", "place");
// set all place labels
svg.selectAll(".place-label")
.data(places.features)
.enter()
.append("text")
.attr("class", function(d) { return "place-label " + d.properties.name; })
.attr("transform", function(d) { return "translate(" + projection(d.geometry.coordinates) + ")"; })
.attr("x", function(d) { return d.geometry.coordinates[0] > -1 ? 6 : -6; })
.attr("dy", ".35em")
.style("text-anchor", function(d) { return d.geometry.coordinates[0] > -1 ? "start" : "end"; })
.text(function(d) { return d.properties.name; });
// tweak specific labels to remove overlap with other labels and routh paths
svg.select(".place-label.Kyoto")
.attr("x", -33)
.attr("dy", "-.15em");
svg.select(".place-label.Uji")
.attr("dy", "-.15em");
svg.select(".place-label.Anhui")
.attr("x", 8);
svg.select(".place-label.Wuyi")
.attr("x", -29);
svg.select(".place-label.Fujian")
.attr("x", -34);
svg.select(".place-label.Nantou")
.attr("x", -40)
.attr("dy", ".01em");
svg.select(".place-label.Alishan")
.attr("dy", ".7em");
svg.select(".place-label.Lishan")
.attr("dy", ".5em");
svg.select(".place-label.Nepal")
.attr("x", -33)
.attr("dy", ".25em");
// add a key
var key = d3.select("body").append("div")
.attr("class", "legend");
key.selectAll(".key")
.data(journey)
.enter()
.append("div")
.attr("class", function(d) {
return "key " + d.name;
})
.style("top", function(d,i) {
if (i >= 7 && i <= 14) {
return "20px";
} else if (i >= 15) {
return "40px";
}
})
.text(function(d) {
return d.name + ": " + d.dates;
});
key.append("div")
.attr("class", "key credit")
.text("Map by: ")
.append("a")
.attr("href", "http://bl.ocks.org/dhoboy")
.attr("target", "_blank")
.text("dhoboy");
});
function constructRoute(journey, places) {
// get the coords of destinations in order
var r = {
type: "LineString",
coordinates: []
};
journey.forEach(function(d) {
places.forEach(function(p) {
if (d.name == p.properties.name) {
d.coords = p.geometry.coordinates;
p.dest = d.dest;
}
})
r.coordinates.push(d.coords);
});
// form coords for curved path drawing
var route = {
type: "MultiLineString",
coordinates: []
};
for (var i = 0; i < r.coordinates.length - 1; i++) {
route.coordinates.push([r.coordinates[i], r.coordinates[i+1]]);
}
return route;
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment