Skip to content

Instantly share code, notes, and snippets.

@webmappergists
Last active August 29, 2015 14:07
Show Gist options
  • Save webmappergists/43202cab650806a04c46 to your computer and use it in GitHub Desktop.
Save webmappergists/43202cab650806a04c46 to your computer and use it in GitHub Desktop.
TopoJSON: mesh and arcs

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

<!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];
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment