By Heber Almeida (http://www.heberonline.com.br) Built with blockbuilder.org
forked from sistemawebpro's block: d3js v4 map + zoom + mark city + drag
license: mit |
By Heber Almeida (http://www.heberonline.com.br) Built with blockbuilder.org
forked from sistemawebpro's block: d3js v4 map + zoom + mark city + drag
<!DOCTYPE html> | |
<head> | |
<meta charset="utf-8"> | |
<script src="https://d3js.org/d3.v4.min.js"></script> | |
<style> | |
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; } | |
</style> | |
</head> | |
<body> | |
<script> | |
const width = 960, | |
height = 500, | |
projection = d3.geoMercator() | |
.center([0, 5]) | |
.scale(200) | |
.rotate([-180, 0]), | |
svg = d3.select('body').append('svg') | |
.attr('width', width) | |
.attr('height', height), | |
path = d3.geoPath() | |
.projection(projection), | |
g = svg.append('g'), | |
cities = [{ 'code': 'ZNZ', 'city': 'ZANZIBAR', 'country': 'TANZANIA', 'lat': '-6.13', 'lon': '39.31' }, { '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' }] | |
g.append('image') | |
.attr('xlink:href', 'https://upload.wikimedia.org/wikipedia/commons/8/80/World_map_-_low_resolution.svg') | |
.append('path') | |
.attr('d', path) | |
// Carregar cidades | load city | |
//d3.json('cities.json', (error, data) => { | |
const circles = g.selectAll('circle') | |
.data(cities) | |
.enter() | |
.append('a') | |
.attr('xlink:href', d => `https://www.google.com/search?q=${d.city}` | |
) | |
.append('circle') | |
.attr('cx', d => projection([d.lon, d.lat])[0]) | |
.attr('cy', d => projection([d.lon, d.lat])[1]) | |
.attr('r', 5) | |
.style('fill', 'red'), | |
drag_handler = d3.drag() | |
.on('start', drag_start) | |
.on('drag', drag_drag) | |
function drag_start() { | |
start_x = +d3.event.x | |
start_y = +d3.event.y | |
} | |
function drag_drag(d) { | |
//Get the current scale of the circle | |
//case where we haven't scaled the circle yet | |
// get lon x lat | |
console.log('lon x lat', projection.invert([d3.event.x, d3.event.y])) | |
if (!this.getAttribute('transform')) | |
current_scale = 1 | |
else { | |
current_scale_string = this.getAttribute('transform').split(' ')[1] | |
current_scale = +current_scale_string.substring(6, current_scale_string.length - 1) | |
} | |
d3.select(this) | |
.attr('cx', d.x = start_x + ((d3.event.x - start_x) / current_scale)) | |
.attr('cy', d.y = start_y + ((d3.event.y - start_y) / current_scale)) | |
} | |
drag_handler(circles) | |
// zoom and pan | |
const zoom = d3.zoom() | |
.on('zoom', () => { | |
g.style('stroke-width', `${1.5 / d3.event.transform.k}px`) | |
g.attr('transform', d3.event.transform) // updated for d3 v4 | |
}) | |
svg.call(zoom) | |
</script> | |
</body> |