Интерактивный глобус с возможностью вращения мышкой и центрированием на выбранную страну. Подробнее о создании можно почитать на Хабрахабре.
This projected is licensed under the terms of the MIT license.
Интерактивный глобус с возможностью вращения мышкой и центрированием на выбранную страну. Подробнее о создании можно почитать на Хабрахабре.
This projected is licensed under the terms of the MIT license.
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="utf-8"> | |
<title>Earth globe</title> | |
<script src="http://d3js.org/d3.v3.min.js"></script> | |
<script src="http://d3js.org/topojson.v1.min.js"></script> | |
<script src="http://d3js.org/queue.v1.min.js"></script> | |
</head> | |
<style type="text/css"> | |
.water { | |
fill: #00248F; | |
} | |
.land { | |
fill: #A98B6F; | |
stroke: #FFF; | |
stroke-width: 0.7px; | |
} | |
.land:hover { | |
fill:#33CC33; | |
stroke-width: 1px; | |
} | |
.focused { | |
fill: #33CC33; | |
} | |
select { | |
position: absolute; | |
top: 20px; | |
left: 580px; | |
border: solid #ccc 1px; | |
padding: 3px; | |
box-shadow: inset 1px 1px 2px #ddd8dc; | |
} | |
.countryTooltip { | |
position: absolute; | |
display: none; | |
pointer-events: none; | |
background: #fff; | |
padding: 5px; | |
text-align: left; | |
border: solid #ccc 1px; | |
color: #666; | |
font-size: 14px; | |
font-family: sans-serif; | |
} | |
</style> | |
<body> | |
<script> | |
var width = 600, | |
height = 500, | |
sens = 0.25, | |
focused; | |
//Setting projection | |
var projection = d3.geo.orthographic() | |
.scale(245) | |
.rotate([0, 0]) | |
.translate([width / 2, height / 2]) | |
.clipAngle(90); | |
var path = d3.geo.path() | |
.projection(projection); | |
//SVG container | |
var svg = d3.select("body").append("svg") | |
.attr("width", width) | |
.attr("height", height); | |
//Adding water | |
svg.append("path") | |
.datum({type: "Sphere"}) | |
.attr("class", "water") | |
.attr("d", path); | |
var countryTooltip = d3.select("body").append("div").attr("class", "countryTooltip"), | |
countryList = d3.select("body").append("select").attr("name", "countries"); | |
queue() | |
.defer(d3.json, "/d/5685937/world-110m.json") | |
.defer(d3.tsv, "/d/5685937/world-110m-country-names.tsv") | |
.await(ready); | |
//Main function | |
function ready(error, world, countryData) { | |
var countryById = {}, | |
countries = topojson.feature(world, world.objects.countries).features; | |
//Adding countries to select | |
countryData.forEach(function(d) { | |
countryById[d.id] = d.name; | |
option = countryList.append("option"); | |
option.text(d.name); | |
option.property("value", d.id); | |
}); | |
//Drawing countries on the globe | |
var world = svg.selectAll("path.land") | |
.data(countries) | |
.enter().append("path") | |
.attr("class", "land") | |
.attr("d", path) | |
//Drag event | |
.call(d3.behavior.drag() | |
.origin(function() { var r = projection.rotate(); return {x: r[0] / sens, y: -r[1] / sens}; }) | |
.on("drag", function() { | |
var rotate = projection.rotate(); | |
projection.rotate([d3.event.x * sens, -d3.event.y * sens, rotate[2]]); | |
svg.selectAll("path.land").attr("d", path); | |
svg.selectAll(".focused").classed("focused", focused = false); | |
})) | |
//Mouse events | |
.on("mouseover", function(d) { | |
countryTooltip.text(countryById[d.id]) | |
.style("left", (d3.event.pageX + 7) + "px") | |
.style("top", (d3.event.pageY - 15) + "px") | |
.style("display", "block") | |
.style("opacity", 1); | |
}) | |
.on("mouseout", function(d) { | |
countryTooltip.style("opacity", 0) | |
.style("display", "none"); | |
}) | |
.on("mousemove", function(d) { | |
countryTooltip.style("left", (d3.event.pageX + 7) + "px") | |
.style("top", (d3.event.pageY - 15) + "px"); | |
}); | |
//Country focus on option select | |
d3.select("select").on("change", function() { | |
var rotate = projection.rotate(), | |
focusedCountry = country(countries, this), | |
p = d3.geo.centroid(focusedCountry); | |
svg.selectAll(".focused").classed("focused", focused = false); | |
//Globe rotating | |
(function transition() { | |
d3.transition() | |
.duration(2500) | |
.tween("rotate", function() { | |
var r = d3.interpolate(projection.rotate(), [-p[0], -p[1]]); | |
return function(t) { | |
projection.rotate(r(t)); | |
svg.selectAll("path").attr("d", path) | |
.classed("focused", function(d, i) { return d.id == focusedCountry.id ? focused = d : false; }); | |
}; | |
}) | |
})(); | |
}); | |
function country(cnt, sel) { | |
for(var i = 0, l = cnt.length; i < l; i++) { | |
if(cnt[i].id == sel.value) {return cnt[i];} | |
} | |
}; | |
}; | |
</script> | |
</body> | |
</html> |
One other thing, there's another instance of "id":-99 in the geo file, and that's Cyprus. The map divides Cyprus into the Turkish-conrolled north and Republic south, but they are one country - http://europa.eu/about-eu/countries/member-countries/cyprus/index_en.htm
Edit
You can locate raw json files at the bottom here: https://gist.github.com/mbostock/4090846
Hey Jason, the countries JSON file is incomplete. Ive found some similar JSON files online, but I was curious if you could share a link to the full file? What makes your json file unique is that the countries are organized by "id" rather than an ISO code.
These are your datasets with updated names. You had Kosovo and Somaliland missing. I've arbitrarily given them the codes 412 and 708 respectively.