1
votes

In a previous question, a user informed me of a great function to center a map and adapt its size to the container.

"There is this nice gist from nrabinowitz, which provides a function which scales and translate a projection to fit a given box. It goes through each of the geodata points (data parameter), projects it (projection parameter), and incrementally update the necessary scale and translation to fit all points in the container (box parameter) while maximizing the scale:

function fitProjection(projection, data, box, center) {
     ...
     return projection.scale(scale).translate([transX, transY])
}

I love this function but for now I would not mind using something that solves my problem. This works for any map, but specifically for the one in Colombia it does not work for me.

I'm trying to center the map to the container so that it fits the center and the size is the right one to the container. but I can not get it to adapt. I have also tried with a .translate and it does not work for me. Is something wrong?

enter image description here

Here is my code:

  function fitProjection(projection, data, box, center) {
      // get the bounding box for the data - might be more efficient approaches
      var left = Infinity,
          bottom = -Infinity,
          right = -Infinity,
          top = Infinity;
      // reset projection
      projection
          .scale(1)
          .translate([0, 0]);
      data.features.forEach(function(feature) {
          d3.geo.bounds(feature).forEach(function(coords) {
              coords = projection(coords);
              var x = coords[0],
                  y = coords[1];
              if (x < left) left = x;
              if (x > right) right = x;
              if (y > bottom) bottom = y;
              if (y < top) top = y;
          });
      });
      // project the bounding box, find aspect ratio
      function width(bb) {
          return (bb[1][0] - bb[0][0])
      }
      function height(bb) {
          return (bb[1][1] - bb[0][1]);
      }
      function aspect(bb) {
          return width(bb) / height(bb);
      }
      var startbox = [[left, top],  [right, bottom]],
          a1 = aspect(startbox),
          a2 = aspect(box),
          widthDetermined = a1 > a2,
          scale = widthDetermined ?
              // scale determined by width
              width(box) / width(startbox) :
              // scale determined by height
              height(box) / height(startbox),
          // set x translation
          transX = box[0][0] - startbox[0][0] * scale,
          // set y translation
          transY = box[0][1] - startbox[0][1] * scale;
      // center if requested
      if (center) {
          if (widthDetermined) {
              transY = transY - (transY + startbox[1][1] * scale - box[1][1])/2;
          } else {
              transX = transX - (transX + startbox[1][0] * scale - box[1][0])/2;
          }
      }
      return projection.scale(scale).translate([transX, transY])
  }

  var width = document.getElementById('statesvg').offsetWidth;
  var height =document.getElementById('statesvg').offsetHeight;     

  /*// Define path generator
  var path = d3.geo.path()               // path generator that will convert GeoJSON to SVG paths
             .projection(projection);  // tell path generator to use albersUsa projection
        */
  //remove svg
   d3.select("#statesvg svg").remove();
  var svg = d3.select("#statesvg")
            .append("svg")
            .attr("width", width+"px")
            .attr("height", height+"px");

   d3.json("https://rawgit.com/john-guerra/43c7656821069d00dcbc/raw/be6a6e239cd5b5b803c6e7c2ec405b793a9064dd/Colombia.geo.json", function(data) {
   var features = data.features;
   var projection=fitProjection(d3.geo.mercator(), data, [[0, 0],  [width, height]], true)
   var path = d3.geo.path()
    .projection(projection);        
        svg.selectAll('path')
        .data(features)
        .enter().append('path')
        .classed('map-layer', true)
        .attr('d', path)
        .attr('vector-effect', 'non-scaling-stroke')


  });

http://plnkr.co/edit/JWL6L7NnhOpwkJeTfO6h?p=preview

1

1 Answers

2
votes

You said that the function...

works for any map, but specifically for the one in Colombia it does not work for me.

This makes no sense: what makes you think that the function has personal issues with Colombia?

The problem is just those islands at the top left corner, the Archipelago of San Andrés, Providencia and Santa Catalina. Let's remove them:

data.features = data.features.filter(function(d){
    return d.properties.DPTO !== "88"
});

Here is the result in my browser:

enter image description here

Here is your updated Plunker: http://plnkr.co/edit/1G0xY7CCCoJv070pdcx4?p=preview