8
votes

I have been trying to make a very simple map on Leaflet for the past two days and am hitting a wall.

I have a topoJSON file with two layers made from previous geoJSON files: US zipcodes for 5 states, and the polygons of the 5 states.

I want to display these on Leaflet and it is important to use topoJSON instead of geoJSON due to the smaller file size with the zip codes layer.

The problem is I cannot for the life of me get even the smaller states layer in my topoJSON file to display on the map. I've looked at lots of examples on the web and followed Mike Bostock's example: https://github.com/mbostock/bost.ocks.org/blob/gh-pages/mike/leaflet/index.html#L131-171.

I can get the file to display in a web browser using just d3, so the file is fine. I'm using v1 of topoJSON along with the topojson.feature method in the script. The code is below. I can't make the topoJSON file available, but I'm assuming it's fine because I've used it with d3 before. If someone could spot something out of whack with the script, that'd be great.

Thanks.

        <!DOCTYPE html>
<meta charset="utf-8">
<head> 
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.6.2/leaflet.css" />
<script src="http://cdn.leafletjs.com/leaflet-0.6.2/leaflet.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script src="http://d3js.org/d3.v2.min.js?2.9.3"></script>
<script src="http://d3js.org/topojson.v1.min.js"></script>
<title>Gulf Zip Codes</title> 
</head>

<div id="map"></div>
<style type="text/css">
#map {
  height: 800px;
}

path {
  fill: #000;
  fill-opacity: .1;
  stroke: #fff;
  stroke-width: 1.5px;
}

path:hover {
  fill: #1f77b4;
  fill-opacity: .4;
}


</style>
<body>

<script>

var map = L.map('map').setView([32.546813, -88.374023], 6);

L.tileLayer('http://{s}.tile.cloudmade.com/1a1b06b230af4efdbb989ea99e9841af/998/256/{z}/{x}/{y}.png', {

attribution: '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);

var svg = d3.select(map.getPanes().overlayPane).append("svg"),
    g = svg.append("g").attr("class", "leaflet-zoom-hide");

d3.json("states_and_codes.json", function(error, states_and_codes) {

  var bounds = d3.geo.bounds(states_and_codes);
    path = d3.geo.path().projection(project);

  var feature = g.selectAll("path")
      .data(topojson.feature(states_and_codes,      states_and_codes.objects.claim_states).features)
    .enter().append("path")
    .attr("class", "path")
    .attr("d",path);

  map.on("viewreset", reset);
  reset();

  // Reposition the SVG to cover the features.
  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);
  }

  // Use Leaflet to implement a D3 geographic projection.
  function project(x) {
    var point = map.latLngToLayerPoint(new L.LatLng(x[1], x[0]));
    return [point.x, point.y];
  } 

});



</script>
</body>
1
Have you inspected the output of the topojson.feature() call? Does it look right? Are you sure the key claim_states is correct and available?nrabinowitz

1 Answers

7
votes

In case your still searching, or for any others out there, this should be the missing piece - bounds of TopoJson;

var bounds = d3.geo.bounds(topojson.feature(states_and_codes, states_and_codes.objects.claim_states));

You will also find here a host of good TopoJson blocks from the source!