This example shows the make up of a TopoJSON file:
- Mesh: individual lines that combined make up a geographic area
- Arcs: nodes where lines coincide
This map is created for a blog post on Webmapper.
Cheers,
Edward @emacgillavry
This example shows the make up of a TopoJSON file:
This map is created for a blog post on Webmapper.
Cheers,
Edward @emacgillavry
<!doctype html> | |
<html lang="en"> | |
<head> | |
<meta charset="utf-8"> | |
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> | |
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" /> | |
<title>TopoJSON in D3 with Leaflet: mesh and arcs</title> | |
<meta name="author" content="Edward Mac Gillavry"> | |
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.css" /> | |
<link rel="stylesheet" href="main.css"> | |
</head> | |
<body> | |
<div id="map-canvas"></div> | |
<script src="http://d3js.org/d3.v3.min.js"></script> | |
<script src="http://d3js.org/topojson.v1.min.js"></script> | |
<script src="http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.js"></script> | |
<script src="main.js"></script> | |
</body> | |
</html> |
body { | |
font: 14px/22px 'Helvetica Neue', Helvetica, Arial, 'Lucida Grande', sans-serif; | |
-webkit-font-smoothing: antialiased; | |
color: #57574D; | |
text-shadow: 1px 1px 1px rgba(0,0,0,0.004); | |
} | |
#map-canvas, html, body { | |
width: 100%; padding: 0; margin: 0; | |
} | |
#map-canvas { | |
height: 450px; | |
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAMAAABhq6zVAAAACVBMVEUAAADl5eX////EwbxGAAAAAXRSTlMAQObYZgAAABFJREFUeAFjYESCKACdT38ZAAWhAAxcPQc7AAAAAElFTkSuQmCC) repeat scroll 0 0 #f9f9f9; | |
cursor: move; | |
-webkit-tap-highlight-color: transparent; | |
} | |
.gemeente { | |
stroke: none; | |
fill: #fff; | |
} | |
.mesh { | |
fill: none; | |
stroke: #666; | |
stroke-width: .5px; | |
stroke-linejoin: round; | |
} | |
.node { | |
stroke:none; | |
fill: #c00; | |
} | |
.leaflet-bar { | |
box-shadow: none; | |
background: none repeat scroll 0 0 rgba(255, 255, 255, 0.4); | |
padding: 2px; | |
} | |
.leaflet-bar a, .leaflet-bar a:hover { | |
background: none repeat scroll 0 0 rgba(160, 195, 63, 1); | |
border-bottom: 1px solid #ccc; | |
color: #fff; | |
display: block; | |
height: 22px; | |
line-height: 19px; | |
text-align: center; | |
text-decoration: none; | |
width: 22px; | |
margin: 1px; | |
font-size: 18px; | |
font-weight: bold; | |
font-family: 'Lucida Grande',Verdana,Geneva,Lucida,Arial,Helvetica,sans-serif; | |
} | |
.leaflet-bar a:hover { | |
background: none repeat scroll 0 0 rgba(145, 177, 55, 1); | |
} | |
.leaflet-control-attribution { | |
background-color: rgba(255,255,255,0.6); | |
font-size: smaller; | |
color: #666; | |
padding: 0 2px; | |
line-height: 22px; | |
} | |
.leaflet-control-attribution a { | |
text-decoration: underline; | |
} |
var bg_map = L.tileLayer('http://a{s}.acetate.geoiq.com/tiles/acetate-bg/{z}/{x}/{y}.png', { | |
attribution: 'Basemap design by <a href="http://www.stamen.com/">Stamen</a>. Tiles hosted by <a href="http://www.geoiq.com/">GeoIQ</a>. Map data: <a href="http://www.openstreetmap.org/">OpenStreetMap</a> contributors and <a href="http://www.naturalearthdata.org/">Natural Earth Data</a>.', | |
subdomains: '0123', | |
minZoom: 2, | |
maxZoom: 18 | |
}); | |
var map = new L.Map('map-canvas', { | |
zoomControl: true, | |
center: [52.2250, 5.1800], | |
zoom: 7, | |
layers: [bg_map] | |
}); | |
map.attributionControl.setPrefix(''); | |
var svg = d3.select(map.getPanes().overlayPane).append('svg'); | |
var g = svg.append('g').attr('class', 'leaflet-zoom-hide'); | |
d3.json('http://places.geocoders.nl/webmapper/dd4eqye9/2013.topo.json', function(error, json) { | |
var collection = topojson.feature(json, json.objects.gemeenten); | |
var tf = json.transform, | |
kx = tf.scale[0], | |
ky = tf.scale[1], | |
dx = tf.translate[0], | |
dy = tf.translate[1]; | |
var bounds = d3.geo.bounds(collection), | |
path = d3.geo.path().projection(project), | |
feature = g.selectAll('path').data(collection.features); | |
feature.enter().append('path') | |
.attr('id', function(d) { return d.id }) | |
.attr('class', 'gemeente') | |
.append('title') | |
.text(function(d) { return d.properties.name }); | |
var mesh = g.append('path') | |
.datum(topojson.mesh(json, json.objects.gemeenten)) | |
.attr('class', 'mesh'); | |
g.selectAll('circle') | |
.data(json.arcs) | |
.enter().append('circle') | |
.attr('class', 'node') | |
.attr('r', 1.5); | |
map.on('viewreset', reset); | |
reset(); | |
function reset() { | |
var bottomLeft = project(bounds[0]), | |
topRight = project(bounds[1]); | |
svg | |
.attr('width', topRight[0] - bottomLeft[0]) | |
.attr('height', bottomLeft[1] - topRight[1]) | |
.style('margin-left', bottomLeft[0] + 'px') | |
.style('margin-top', topRight[1] + 'px'); | |
g | |
.attr('transform', 'translate(' + -bottomLeft[0] + ',' + -topRight[1] + ')'); | |
feature | |
.attr('d', path); | |
mesh | |
.attr('d', path); | |
g.selectAll('circle') | |
.attr('cx', function(d) { return project([d[0][0] * kx + dx, d[0][1] * ky + dy])[0] }) | |
.attr('cy', function(d) { return project([d[0][0] * kx + dx, d[0][1] * ky + dy])[1] }); | |
} | |
function project(x) { | |
var point = map.latLngToLayerPoint(new L.LatLng(x[1], x[0])); | |
return [point.x, point.y]; | |
} | |
}); |