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]; | |
| } | |
| }); |