Inspired by Secret Country
Forked from World tour
| license: gpl-3.0 |
Inspired by Secret Country
Forked from World tour
| <!DOCTYPE html> | |
| <meta charset="utf-8"> | |
| <title>Secret Country: World Tour</title> | |
| <style> | |
| h1 { | |
| position: absolute; | |
| top: 500px; | |
| font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; | |
| font-size: 18px; | |
| text-align: center; | |
| width: 640px; | |
| } | |
| .control { | |
| top: 10px; | |
| text-align: center; | |
| width: 640px; | |
| } | |
| .credits { | |
| position:absolute; | |
| bottom: 0; | |
| text-align: center; | |
| width: 640px; | |
| } | |
| </style> | |
| <h1></h1> | |
| <div class="control"> | |
| <div>Find the secret country! Green means close, yellow means far.</div> | |
| <input type="text" id="country"></input> <br> | |
| <button id="cheat">Cheat</button> | |
| </div> | |
| <div> | |
| All the hard parts were done by Mike Bostock in <a href='https://bl.ocks.org/mbostock/4183330'>World tour</a>. | |
| Inspired by Sporcle's <a href='https://www.sporcle.com/g00/games/goc3/hidden-country-i'>Secret Country</a>. | |
| </div> | |
| <script src="//d3js.org/d3.v3.min.js"></script> | |
| <script src="//d3js.org/queue.v1.min.js"></script> | |
| <script src="//d3js.org/topojson.v1.min.js"></script> | |
| <script> | |
| var width = 640, | |
| height = 640; | |
| var projection = d3.geo.orthographic() | |
| .translate([width / 2, height / 2]) | |
| .scale(width / 2 - 20) | |
| .clipAngle(90) | |
| .precision(0.6); | |
| var canvas = d3.select("body").append("canvas") | |
| .attr("width", width) | |
| .attr("height", height); | |
| var c = canvas.node().getContext("2d"); | |
| var path = d3.geo.path() | |
| .projection(projection) | |
| .context(c); | |
| var title = d3.select("h1"); | |
| var scale = d3.scale.linear() | |
| .domain([0, 2.5]) | |
| .range(["green", "yellow", "red"]); | |
| queue() | |
| .defer(d3.json, "/mbostock/raw/4090846/world-110m.json") | |
| .defer(d3.tsv, "/mbostock/raw/4090846/world-country-names.tsv") | |
| .await(ready); | |
| var synonyms = {"russia":"russian federation"} | |
| function ready(error, world, names) { | |
| if (error) throw error; | |
| var globe = {type: "Sphere"}, | |
| 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 !== b; }), | |
| i = -1, | |
| n = countries.length; | |
| countries = countries.filter(function(d) { | |
| return names.some(function(n) { | |
| if (d.id == n.id) return d.name = n.name; | |
| }); | |
| }).sort(function(a, b) { | |
| return a.name.localeCompare(b.name); | |
| }); | |
| function transition_to(country) { | |
| d3.transition() | |
| .duration(1250) | |
| .each("start", function() { | |
| title.text(country.name); | |
| }) | |
| .tween("rotate", function() { | |
| var p = d3.geo.centroid(country), | |
| r = d3.interpolate(projection.rotate(), [-p[0], -p[1]]); | |
| return function(t) { | |
| projection.rotate(r(t)); | |
| c.clearRect(0, 0, width, height); | |
| c.fillStyle = "#ccc", c.beginPath(), path(land), c.fill(); | |
| countries.forEach(function(d) { | |
| if (d.col) { | |
| c.fillStyle = d.col, c.beginPath(), path(d), c.fill(); | |
| } | |
| }) | |
| c.strokeStyle = "#fff", c.lineWidth = .5, c.beginPath(), path(borders), c.stroke(); | |
| c.strokeStyle = "#000", c.lineWidth = 2, c.beginPath(), path(globe), c.stroke(); | |
| }; | |
| }).each("end", function() { | |
| if (country.name == secret.name) | |
| alert("You found the secret country!"); | |
| }) | |
| } | |
| // start | |
| c.clearRect(0, 0, width, height); | |
| c.fillStyle = "#ccc", c.beginPath(), path(land), c.fill(); | |
| c.strokeStyle = "#fff", c.lineWidth = .5, c.beginPath(), path(borders), c.stroke(); | |
| c.strokeStyle = "#000", c.lineWidth = 2, c.beginPath(), path(globe), c.stroke(); | |
| var secret = countries[Math.floor(Math.random() * countries.length)] | |
| console.log(secret) | |
| d3.select("#country").on("change", function() { | |
| var name = this.value; | |
| name = synonyms[name.toLowerCase()] || name; | |
| var filtered = countries.filter(function(d) { return d.name.toLowerCase() == name.toLowerCase(); }); | |
| if (filtered.length > 0) { | |
| var country = filtered[0]; | |
| var distance = d3.geo.distance(d3.geo.centroid(country), d3.geo.centroid(secret)); | |
| country.col = scale(distance) | |
| transition_to(country); | |
| } | |
| }) | |
| d3.select("#cheat").on("click", function() { | |
| secret.col = scale(0); | |
| transition_to(secret) | |
| }) | |
| } | |
| d3.select(self.frameElement).style("height", height + "px"); | |
| </script> |