Center a map in d3 given a geoJSON object

后端 未结 11 2211
慢半拍i
慢半拍i 2020-11-21 22:55

Currently in d3 if you have a geoJSON object that you are going to draw you have to scale it and translate it in order to get it to the size that one wants and translate it

相关标签:
11条回答
  • 2020-11-21 23:26

    To pan/zoom the map you should look at overlaying the SVG on Leaflet. That will be a lot easier than transforming the SVG. See this example http://bost.ocks.org/mike/leaflet/ and then How to change the map center in leaflet

    0 讨论(0)
  • 2020-11-21 23:29

    With d3 v4 or v5 its getting way easier!

    var projection = d3.geoMercator().fitSize([width, height], geojson);
    var path = d3.geoPath().projection(projection);
    

    and finally

    g.selectAll('path')
      .data(geojson.features)
      .enter()
      .append('path')
      .attr('d', path)
      .style("fill", "red")
      .style("stroke-width", "1")
      .style("stroke", "black");
    

    Enjoy, Cheers

    0 讨论(0)
  • 2020-11-21 23:33

    I was looking around on the Internet for a fuss-free way to center my map, and got inspired by Jan van der Laan and mbostock's answer. Here's an easier way using jQuery if you are using a container for the svg. I created a border of 95% for padding/borders etc.

    var width = $("#container").width() * 0.95,
        height = $("#container").width() * 0.95 / 1.9 //using height() doesn't work since there's nothing inside
    
    var projection = d3.geo.mercator().translate([width / 2, height / 2]).scale(width);
    var path = d3.geo.path().projection(projection);
    
    var svg = d3.select("#container").append("svg").attr("width", width).attr("height", height);
    

    If you looking for exact scaling, this answer won't work for you. But if like me, you wish to display a map that centralizes in a container, this should be enough. I was trying to display the mercator map and found that this method was useful in centralizing my map, and I could easily cut off the Antarctic portion since I didn't need it.

    0 讨论(0)
  • 2020-11-21 23:34

    The following seems to do approximately what you want. The scaling seems to be ok. When applying it to my map there is a small offset. This small offset is probably caused because I use the translate command to center the map, while I should probably use the center command.

    1. Create a projection and d3.geo.path
    2. Calculate the bounds of the current projection
    3. Use these bounds to calculate the scale and translation
    4. Recreate the projection

    In code:

      var width  = 300;
      var height = 400;
    
      var vis = d3.select("#vis").append("svg")
          .attr("width", width).attr("height", height)
    
      d3.json("nld.json", function(json) {
          // create a first guess for the projection
          var center = d3.geo.centroid(json)
          var scale  = 150;
          var offset = [width/2, height/2];
          var projection = d3.geo.mercator().scale(scale).center(center)
              .translate(offset);
    
          // create the path
          var path = d3.geo.path().projection(projection);
    
          // using the path determine the bounds of the current map and use 
          // these to determine better values for the scale and translation
          var bounds  = path.bounds(json);
          var hscale  = scale*width  / (bounds[1][0] - bounds[0][0]);
          var vscale  = scale*height / (bounds[1][1] - bounds[0][1]);
          var scale   = (hscale < vscale) ? hscale : vscale;
          var offset  = [width - (bounds[0][0] + bounds[1][0])/2,
                            height - (bounds[0][1] + bounds[1][1])/2];
    
          // new projection
          projection = d3.geo.mercator().center(center)
            .scale(scale).translate(offset);
          path = path.projection(projection);
    
          // add a rectangle to see the bound of the svg
          vis.append("rect").attr('width', width).attr('height', height)
            .style('stroke', 'black').style('fill', 'none');
    
          vis.selectAll("path").data(json.features).enter().append("path")
            .attr("d", path)
            .style("fill", "red")
            .style("stroke-width", "1")
            .style("stroke", "black")
        });
    
    0 讨论(0)
  • 2020-11-21 23:37

    There is a center() method you can use that accepts a lat/lon pair.

    From what I understand, translate() is only used for literally moving the pixels of the map. I am not sure how to determine what scale is.

    0 讨论(0)
提交回复
热议问题