Интерактивный глобус с возможностью вращения мышкой и центрированием на выбранную страну. Подробнее о создании можно почитать на Хабрахабре.
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> |
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.