|
<!DOCTYPE html> |
|
<meta charset="utf-8"> |
|
<style> |
|
|
|
svg { |
|
background: #efefef; |
|
} |
|
|
|
.sphere { |
|
fill: #000; |
|
} |
|
|
|
.land { |
|
fill: grey; |
|
} |
|
|
|
.boundary { |
|
fill: none; |
|
stroke: #660000; |
|
stroke-linejoin: round; |
|
stroke-linecap: round; |
|
vector-effect: non-scaling-stroke; |
|
} |
|
|
|
|
|
</style> |
|
<script src="http://d3js.org/d3.v4.min.js"></script> |
|
<script src="http://d3js.org/topojson.v1.min.js"></script> |
|
<body> |
|
<button id="zoom-in">+</button> |
|
<button id="zoom-out">-</button> |
|
<script> |
|
|
|
|
|
var width = 960, |
|
height = 960, |
|
center = [width / 2, height / 2], |
|
cities = [{ 'code': 'OTT', 'city': 'OTTAWA', 'country': 'CANADA', 'lat': '23.10', 'lon': '120.34' }, { 'code': 'BSB', 'city': 'BRASILIA', 'country': 'BRAZIL', 'lat': '-32.85', 'lon': '133.30' }, { 'code': 'DEL', 'city': 'DELHI', 'country': 'INDIA', 'lat': '4.71', 'lon': '-127.57' }, { 'code': 'CMX', 'city': 'CIDADE DO MÉXICO', 'country': 'MÉXICO', 'lat': '0.42', 'lon': '93.19' }, { 'code': 'SID', 'city': 'SIDNEY', 'country': 'AUSTRALIA', 'lat': '-48.38', 'lon': '-71.71' }, { 'code': 'TOK', 'city': 'TOQUIO', 'country': 'JAPÃO', 'lat': '17.34', 'lon': '-81.73' }, { 'code': 'CCA', 'city': 'CIDADE DO CABO', 'country': 'AFRICA DO SUL', 'lat': '-43.20', 'lon': '-171.97' }, { 'code': 'CMP', 'city': 'CAMPO GRANDE', 'country': 'BRASIL', 'lat': '-36.15', 'lon': '130.72' }, { 'code': 'PAR', 'city': 'PARIS', 'country': 'FRANÇA', 'lat': '22.19', 'lon': '174.27' }, { 'code': 'NOY', 'city': 'NOVA YORK', 'country': 'USA', 'lat': '11.23', 'lon': '112.96' }]; |
|
|
|
var projection = d3.geoMercator() |
|
.translate([width / 2, height / 2]) |
|
.scale((width - 1) / 2 / Math.PI); |
|
|
|
var zoom = d3.zoom() |
|
.scaleExtent([1, 8]) |
|
.on("zoom", zoomed); |
|
|
|
var path = d3.geoPath() |
|
.projection(projection); |
|
|
|
|
|
var svg = d3.select("body").append("svg") |
|
.attr("width", width) |
|
.attr("height", height) |
|
.append("g"); |
|
|
|
var g = svg.append("g"); |
|
|
|
svg.call(zoom); |
|
|
|
d3.json("https://gist.githubusercontent.com/mbostock/4090846/raw/d534aba169207548a8a3d670c9c2cc719ff05c47/world-50m.json", function(error, world) { |
|
g.append("path") |
|
.datum({type: "Sphere"}) |
|
.attr("class", "sphere") |
|
.attr("d", path); |
|
|
|
g.append("path") |
|
.datum(topojson.merge(world, world.objects.countries.geometries)) |
|
.attr("class", "land") |
|
.attr("d", path); |
|
|
|
g.append("path") |
|
.datum(topojson.mesh(world, world.objects.countries, function(a, b) { return a !== b; })) |
|
.attr("class", "boundary") |
|
.attr("d", path); |
|
|
|
const circles = g.selectAll('circle') |
|
.data(cities) |
|
.enter() |
|
.append('a') |
|
.attr('xlink:href', d => `https://www.google.com/search?q=${d.city}` |
|
) |
|
.append('rect') |
|
.attr('x', d => projection([d.lon, d.lat])[0]) |
|
.attr('y', d => projection([d.lon, d.lat])[1]) |
|
.attr('width', 10) |
|
.attr('height', 10) |
|
.style('fill', 'yellow'); |
|
|
|
|
|
}); |
|
|
|
function zoomed() { |
|
var transform = d3.event.transform; |
|
|
|
g.style("stroke-width", 1.5 / transform.k + "px"); |
|
g.attr("transform", transform); |
|
} |
|
|
|
d3.select(self.frameElement).style("height", height + "px"); |
|
|
|
var intervalID; |
|
|
|
d3.select('#zoom-in').on('click', function() { |
|
// Smooth zooming |
|
zoom.scaleBy(svg.transition().duration(750), 1.3); |
|
}); |
|
|
|
d3.select('#zoom-out').on('click', function() { |
|
// Ordinal zooming |
|
zoom.scaleBy(svg, 1 / 1.3); |
|
}); |
|
|
|
|
|
|
|
</script> |