Built with blockbuilder.org
forked from da1fujimoto's block: topojson Map
license: mit |
Built with blockbuilder.org
forked from da1fujimoto's block: topojson Map
<!-- | |
Adapted from Mike Bostock at bl.ocks.org | |
https://bl.ocks.org/mbostock/3734333 | |
--> | |
<!DOCTYPE html> | |
<head> | |
<meta charset="utf-8"> | |
<meta name="description" content=""> | |
<title>8.2 - Visualization around the globe</title> | |
<!-- Custom CSS --> | |
<link rel="stylesheet" href="style.css"> | |
</head> | |
<body> | |
<div class="canvas"></div> | |
<script src="https://d3js.org/d3.v5.min.js"></script> | |
<script src="https://d3js.org/topojson.v2.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3-tip/0.9.1/d3-tip.min.js"></script> | |
<script src="main.js"></script> | |
</body> |
[ | |
{"name": "Japan", "latitude": 36.4940952757612, "longitude": 136.5326249599457} | |
] |
const svg = d3.select('.canvas').append('svg') | |
.attr('width', 960) | |
.attr('height', 500); | |
const margin = { | |
top: 50, | |
right: 30, | |
bottom: 50, | |
left: 30 | |
}; | |
const width = svg.attr('width') - margin.left - margin.right; | |
const height = svg.attr('height') - margin.top - margin.bottom; | |
const g = svg.append('g') | |
.attr('transform', `translate(${margin.left}, ${margin.top})`); | |
const projection = d3.geoNaturalEarth1() | |
.scale(150) | |
.translate([width / 2, height / 2]) | |
.precision(.1); | |
const path = d3.geoPath() | |
.projection(projection); | |
const graticule = d3.geoGraticule(); | |
const tip = d3.tip() | |
.attr('class', 'd3-tip') | |
.offset([-10, 0]) | |
.html(d => `<p>${d.name}</p><p>lat: ${d.latitude}</p><p>lon: ${d.longitude}</p>`); | |
g.call(tip); | |
const promises = [ | |
d3.json('world-110m.json'), | |
d3.json('locations.json') | |
]; | |
Promise.all(promises).then(dataAll => { | |
const world = dataAll[0]; | |
/* 陸地 */ | |
g.append("path") | |
.datum(topojson.feature(world, world.objects.land)) | |
.attr("class", "land") | |
.attr("d", path); | |
/* 国境 */ | |
g.append("path") | |
.datum(topojson.mesh(world, world.objects.countries, (a, b) => a !== b)) | |
.attr("class", "boundary") | |
.attr("d", path); | |
/* 緯度経度 */ | |
g.append("path") | |
.datum(graticule) | |
.attr("class", "graticule") | |
.attr("d", path); | |
const locations = dataAll[1]; | |
const markers = g.append('g') | |
.selectAll('circle') | |
.data(locations) | |
markers.enter() | |
.append('circle') | |
.attr('cx', d => projection([d.longitude, d.latitude])[0]) | |
.attr('cy', d => projection([d.longitude, d.latitude])[1]) | |
.attr('fill', 'red') | |
.attr('r', 5) | |
.on('mouseover', tip.show) | |
.on('mouseout', tip.hide) | |
}).catch(err => { | |
console.error(err); | |
}); |
svg { | |
margin-left: auto; | |
margin-right: auto; | |
display: block; | |
} | |
.graticule { | |
fill: none; | |
stroke: #777; | |
stroke-width: .5px; | |
stroke-opacity: .5; | |
} | |
.land { | |
fill: #999; | |
} | |
.boundary { | |
fill: none; | |
stroke: #fff; | |
stroke-width: .5px; | |
} | |
.d3-tip { | |
line-height: 1; | |
font-weight: bold; | |
padding: 10px; | |
background: rgba(0, 0, 0, 0.8); | |
color: #fff; | |
border-radius: 2px; | |
font-size: 10px; | |
} | |
.d3-tip:after { | |
box-sizing: border-box; | |
display: inline; | |
font-size: 10px; | |
width: 100%; | |
line-height: 1; | |
color: rgba(0, 0, 0, 0.8); | |
content: "\25BC"; | |
position: absolute; | |
text-align: center; | |
} | |
.d3-tip.n:after { | |
margin: -1px 0 0 0; | |
top: 100%; | |
left: 0; | |
} |