|
<!DOCTYPE html> |
|
<meta charset="utf-8"> |
|
<style> |
|
.graticule { |
|
fill: none; |
|
stroke: #777; |
|
stroke-width: .5px; |
|
stroke-opacity: .5; |
|
} |
|
|
|
.land { |
|
fill: none; |
|
stroke-width: .5px; |
|
stroke-opacity: .5; |
|
} |
|
|
|
.boundary { |
|
fill: none; |
|
stroke: #fff; |
|
stroke-width: .5px; |
|
} |
|
|
|
.country { |
|
fill: #ccc; |
|
} |
|
|
|
.country.eurocontrol { |
|
fill: rgb(51,154,205); |
|
} |
|
|
|
.country-label { |
|
fill: #fff; |
|
fill-opacity: 1.0; |
|
font-size: 20px; |
|
font-weight: 300; |
|
text-anchor: middle; |
|
} |
|
|
|
#loading { |
|
text-align: center; |
|
position: absolute; |
|
padding-left: 200px; |
|
padding-top: 100px; |
|
height: 20px; |
|
font-size: 30px; |
|
} |
|
|
|
#tooltip { |
|
position: absolute; |
|
width: auto; |
|
height: auto; |
|
padding: 2px 2px; |
|
-webkit-border-radius: 3px; |
|
-moz-border-radius: 3px; |
|
border-radius: 3px; |
|
-webkit-box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.4); |
|
-moz-box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.4); |
|
box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.4); |
|
pointer-events: none; |
|
background-color: #bbb; |
|
} |
|
|
|
#tooltip.hidden { |
|
display: none; |
|
} |
|
|
|
#tooltip p { |
|
margin: 0 0 0 0; |
|
padding: 2px 2px; |
|
font-family: sans-serif; |
|
font-size: 14px; |
|
} |
|
|
|
#countryflag { |
|
display: block; |
|
max-width: 120px; |
|
max-height: 100px; |
|
width: auto; |
|
height: auto; |
|
} |
|
|
|
#coordinates { |
|
position: absolute; |
|
text-align: left; |
|
font-size: 12px; |
|
font-family:Arial,Helvetica,sans-serif |
|
} |
|
|
|
.hidden{ |
|
display: none; |
|
} |
|
|
|
</style> |
|
<body> |
|
<div id="tooltip" class="hidden"> |
|
<p id="countryname"></p> |
|
<p id="adhesiondate"></p> |
|
<img id="countryflag"> |
|
</div> |
|
<div id="map"> |
|
<div id="loading">Loading...</div> |
|
</div> |
|
|
|
<script src="http://d3js.org/d3.v3.min.js"></script> |
|
<script src="http://d3js.org/queue.v1.min.js"></script> |
|
<script src="http://d3js.org/topojson.v1.min.js"></script> |
|
<script src="http://keithcirkel.co.uk/jwerty/jwerty.js"></script> |
|
<script> |
|
|
|
var width = 960, |
|
height = 600; |
|
|
|
|
|
// // ############### scaling and translating ############### |
|
// from http://stackoverflow.com/questions/14492284/#answer-14691788 |
|
// var N = 71, |
|
// E = -11, |
|
// W = 35, |
|
// S = 34, |
|
// europe = { "type": "Polygon", |
|
// "coordinates": [ |
|
// [ |
|
// [E, N], |
|
// [W, N], |
|
// [W, S], |
|
// [E, S] |
|
// ] ] |
|
// }; |
|
|
|
// // find proper scale and translation from bounds of europe polygon |
|
// var projection = d3.geo.azimuthalEqualArea().scale(1).translate([0,0]).clipAngle(180 - 1e-3).precision(0.1); |
|
// var path = d3.geo.path().projection(projection); |
|
// var b = path.bounds(europe), |
|
// s = .95 / Math.max((b[1][0] - b[0][0]) / width, (b[1][1] - b[0][1]) / height), |
|
// t = [(width - s * (b[1][0] + b[0][0])) / 2, (height - s * (b[1][1] + b[0][1])) / 2]; |
|
|
|
// console.log("scale="+s); |
|
// console.log("translate="+t); |
|
// // ####################################################### |
|
|
|
var s = 987, |
|
t = [262, 1187]; |
|
|
|
var projection = d3.geo.azimuthalEqualArea().scale(s).translate(t).clipAngle(180 - 1e-3).precision(1), |
|
path = d3.geo.path().projection(projection); |
|
|
|
var graticule = d3.geo.graticule(); |
|
var loading = d3.select("#loading"); |
|
var svg = d3.select("#map").append("svg") |
|
.attr("width", width) |
|
.attr("height", height); |
|
|
|
var tooltip = d3.select("#tooltip").classed("hidden", true), |
|
countryname = d3.select("#countryname"), |
|
adhesiondate = d3.select("#adhesiondate"), |
|
countryflag = d3.select("#countryflag"), |
|
format = d3.format(" 2.2f"); |
|
|
|
svg.on("mousemove", function() { |
|
// update tooltip position |
|
tooltip.style("top", (event.pageY-10)+"px").style("left",(event.pageX+10)+"px"); |
|
return true; |
|
}); |
|
|
|
var logo = svg.append("g"); |
|
logo.append("image") |
|
.attr("xlink:href", |
|
"http://upload.wikimedia.org/wikipedia/commons/b/b2/Eurocontrol_logo_2010.svg") |
|
.attr("x", 40) |
|
.attr("y", 160) |
|
.attr("width", 100) |
|
.attr("height", 100) |
|
.attr("preserveAspectRatio", "xMinYMin"); |
|
|
|
svg.append("path") |
|
.datum(graticule) |
|
.attr("class", "graticule") |
|
.attr("d", path); |
|
|
|
queue() |
|
.defer(d3.json, "/mbostock/raw/4090846/world-50m.json") |
|
.defer(d3.tsv, "/mbostock/raw/4090846/world-country-names.tsv") |
|
.defer(d3.tsv, "/espinielli/raw/5107491/world-country-flags.tsv") |
|
.defer(d3.tsv, "eurocontrol_members.tsv") |
|
.await(ready); |
|
|
|
function ready(error, world, names, flags, members) { |
|
if (error) return console.error(error); |
|
loading.classed("hidden", true); |
|
var land = topojson.feature(world, world.objects.land), |
|
countries = topojson.feature(world, world.objects.countries).features, |
|
borders = topojson.mesh(world, world.objects.countries,function(a, b) { return a.id !== b.id; }), |
|
eurocontrol = d3.set(); |
|
|
|
for (var i = members.length - 1; i >= 0; i--) { |
|
eurocontrol.add(members[i].id); |
|
}; |
|
|
|
countries.forEach(function(d) { |
|
names.some(function(n) { |
|
if (d.id == n.id) return d.name = n.name; |
|
}); |
|
}); |
|
|
|
countries.forEach(function(d) { |
|
members.some(function(n) { |
|
if (d.id == n.id) { |
|
d.adhesion = n.date; |
|
return d.iso2 = n.iso2; |
|
} |
|
}); |
|
}); |
|
|
|
countries.forEach(function(d) { |
|
flags.some(function(n) { |
|
if (d.id == n.id) return d.flag = n.url; |
|
}); |
|
}); |
|
|
|
var country = svg.selectAll(".country") |
|
.data(countries) |
|
.enter().insert("path", ".graticule") |
|
.attr("class", function(d) {return (eurocontrol.has(d.id)? "country eurocontrol": "country");}) |
|
.attr("d", path) |
|
.text(function(d) { return d.id;}) |
|
.on("mouseover", function(d,i) { |
|
d3.select(this).style({'stroke-opacity':1,'stroke':'#F00'}); |
|
// http://stackoverflow.com/questions/17917072/#answer-17917341 |
|
// d3.select(this.parentNode.appendChild(this)).style({'stroke-opacity':1,'stroke':'#F00'}); |
|
if (eurocontrol.has(d.id)) { |
|
tooltip.classed("hidden", false); |
|
countryname.text(d.name); |
|
adhesiondate.text("(" + d.adhesion + ")"); |
|
countryflag.attr("src", d.flag); |
|
} |
|
}) |
|
.on("mouseout", function(d) { |
|
this.style.stroke = "none"; |
|
tooltip.classed("hidden", true); |
|
}) |
|
.on("mousedown.log", function(d) { |
|
console.log("id=" + d.id + "; name=" + d.name + "; centroid=[" + path.centroid(d) + "] px."); |
|
});; |
|
|
|
// add ISO2 label |
|
// svg.selectAll(".eurocontrol") |
|
// .append("text") |
|
// .attr("class", function(d) { return "country-label " + d.iso2; }) |
|
// .attr("transform", function(d) { return "translate(" + path.centroid(d) + ")"; }) |
|
// .attr("z-index", 1000) |
|
// .attr("dy", ".35em") |
|
// .text(function(d) { return d.iso2;}); |
|
|
|
svg.insert("path", ".graticule") |
|
.datum(land) |
|
.attr("class", "land") |
|
.attr("d", path); |
|
|
|
svg.insert("path", ".graticule") |
|
.datum(borders) |
|
.attr("class", "boundary") |
|
.attr("d", path); |
|
}; |
|
|
|
d3.select(self.frameElement).style("height", height + "px"); |
|
</script> |