使用d3.js和geojson显示地图

15

我正在研究D3的地理模块。虽然我有一些D3的经验,但这是我第一次尝试使用地理模块。我采用了以下代码 (来自https://github.com/alignedleft/d3-book/blob/master/chapter_12/04_fill.html),该代码最初显示美国地图 (https://github.com/alignedleft/d3-book/edit/master/chapter_12/us-states.json) 编辑 (文件现在可以在可下载的zip文件中找到,该文件可从https://github.com/alignedleft/d3-book/releases/tag/v1.0下载) ,使用阿尔伯斯投影,并修改为使用印度的Geojson文件(indiastates1.json)。 该代码可以很好地与美国文件配合使用,但是使用印度的json文件时则没有显示任何内容。 请问我漏掉了什么?非常感谢您的帮助。我已将投影更改为墨卡托投影。

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>D3: Setting path fills</title>
        <script type="text/javascript" src="../d3/d3.v3.js"></script>
        <style type="text/css">
            /* No style rules here yet */       
        </style>
    </head>
    <body>
        <script type="text/javascript">

            //Width and height
            var w = 500;
            var h = 300;

            //Define map projection
            var projection = d3.geo.mercator()
                                   .translate([w/2, h/2])
                                   .scale([500]);

            //Define path generator
            var path = d3.geo.path()
                             .projection(projection);

            //Create SVG element
            var svg = d3.select("body")
                        .append("svg")
                        .attr("width", w)
                        .attr("height", h);

            //Load in GeoJSON data
            d3.json("indiastates1.json", function(json) {

                //Bind data and create one path per GeoJSON feature
                svg.selectAll("path")
                   .data(json.features)
                   .enter()
                   .append("path")
                   .attr("d", path)
                   .style("fill", "steelblue");

            });

        </script>
    </body>
</html>

印度各邦的1号数据文件indiastates1.json

{"type":"FeatureCollection","features":[
{"type":"Feature","id":"IND","properties":{"name":"India"},"geometry":{"type":"Polygon","coordinates":[[[77.837451,35.49401],[78.912269,34.321936],[78.811086,33.506198],[79.208892,32.994395],[79.176129,32.48378],[78.458446,32.618164],[78.738894,31.515906],[79.721367,30.882715],[81.111256,30.183481],[80.476721,29.729865],[80.088425,28.79447],[81.057203,28.416095],[81.999987,27.925479],[83.304249,27.364506],[84.675018,27.234901],[85.251779,26.726198],[86.024393,26.630985],[87.227472,26.397898],[88.060238,26.414615],[88.174804,26.810405],[88.043133,27.445819],[88.120441,27.876542],[88.730326,28.086865],[88.814248,27.299316],[88.835643,27.098966],[89.744528,26.719403],[90.373275,26.875724],[91.217513,26.808648],[92.033484,26.83831],[92.103712,27.452614],[91.696657,27.771742],[92.503119,27.896876],[93.413348,28.640629],[94.56599,29.277438],[95.404802,29.031717],[96.117679,29.452802],[96.586591,28.83098],[96.248833,28.411031],[97.327114,28.261583],[97.402561,27.882536],[97.051989,27.699059],[97.133999,27.083774],[96.419366,27.264589],[95.124768,26.573572],[95.155153,26.001307],[94.603249,25.162495],[94.552658,24.675238],[94.106742,23.850741],[93.325188,24.078556],[93.286327,23.043658],[93.060294,22.703111],[93.166128,22.27846],[92.672721,22.041239],[92.146035,23.627499],[91.869928,23.624346],[91.706475,22.985264],[91.158963,23.503527],[91.46773,24.072639],[91.915093,24.130414],[92.376202,24.976693],[91.799596,25.147432],[90.872211,25.132601],[89.920693,25.26975],[89.832481,25.965082],[89.355094,26.014407],[88.563049,26.446526],[88.209789,25.768066],[88.931554,25.238692],[88.306373,24.866079],[88.084422,24.501657],[88.69994,24.233715],[88.52977,23.631142],[88.876312,22.879146],[89.031961,22.055708],[88.888766,21.690588],[88.208497,21.703172],[86.975704,21.495562],[87.033169,20.743308],[86.499351,20.151638],[85.060266,19.478579],[83.941006,18.30201],[83.189217,17.671221],[82.192792,17.016636],[82.191242,16.556664],[81.692719,16.310219],[80.791999,15.951972],[80.324896,15.899185],[80.025069,15.136415],[80.233274,13.835771],[80.286294,13.006261],[79.862547,12.056215],[79.857999,10.357275],[79.340512,10.308854],[78.885345,9.546136],[79.18972,9.216544],[78.277941,8.933047],[77.941165,8.252959],[77.539898,7.965535],[76.592979,8.899276],[76.130061,10.29963],[75.746467,11.308251],[75.396101,11.781245],[74.864816,12.741936],[74.616717,13.992583],[74.443859,14.617222],[73.534199,15.990652],[73.119909,17.92857],[72.820909,19.208234],[72.824475,20.419503],[72.630533,21.356009],[71.175273,20.757441],[70.470459,20.877331],[69.16413,22.089298],[69.644928,22.450775],[69.349597,22.84318],[68.176645,23.691965],[68.842599,24.359134],[71.04324,24.356524],[70.844699,25.215102],[70.282873,25.722229],[70.168927,26.491872],[69.514393,26.940966],[70.616496,27.989196],[71.777666,27.91318],[72.823752,28.961592],[73.450638,29.976413],[74.42138,30.979815],[74.405929,31.692639],[75.258642,32.271105],[74.451559,32.7649],[74.104294,33.441473],[73.749948,34.317699],[74.240203,34.748887],[75.757061,34.504923],[76.871722,34.653544],[77.837451,35.49401]]]}}
]}
3个回答

12

你(或者浏览器)只是在错误的位置查找。我认为d3会自动以这些地理投影方式将地图居中于美国。你需要做的就是使用transform将“印度”移动到svg视口上。具体来说,你需要将视口的原点平移至由x,y像素坐标指定的位置 - 至少我是这么想的。为了看到印度,我尝试了:

.attr("transform", "translate(-800,200)")

看起来它似乎能胜任这个工作。

如果您检查元素,很容易就能掌握这些内容,然后可以使用路径为您提供一些提示,以便进行转换。

更新

解决这个问题的更好方法是计算中心和比例,如此问题和答案所述。特别是Jan和Mike的答案都非常出色。在这个Google Groups讨论中也有代码的解释 - 倒数第二篇帖子。


非常感谢。我明白了。我也怀疑是类似的问题,因为在Chrome上,控制台没有抛出任何错误,并且当我在元素上点击SVG时,它似乎在浏览器的某个地方突出显示,但不知道在哪里!所以问题就在于找到正确的转换来重新定位它。你是通过试错来找到正确的转换数字的吗? - Ratnakar Vellanki
1
路径(即在d =之后的位,如M150.158 128.215,486.1589Z)告诉您它在哪里显示。 在这个虚构的例子中,数字表明路径从150开始,在您的例子中,我认为第一个数字大约是900,所以我将视口向左移动了800并向下移动了一点,因为检查器显示它仅在屏幕顶部。 要获得更完整的答案,请尝试此链接:https://dev59.com/ymYq5IYBdhLWcg3wbgDk - user1614080

2
这是一个简单的示例,展示了如何将你的地图投影中心放在你特征集合中的所有特征上(而不仅仅是一个或默认值)。它基于Mike Bostock的答案,这个答案非常好,但是只基于缩放一个特征,并且d3.js geoJSON和bounds也显示可以使用整个特征集合。
你的代码的关键更改是:
  • Replacing the initial translate and scale with a neutral one:

       var projection = d3.geo.mercator()
           .scale(1)
           .translate([0, 0]);
    
  • After loading the json, adding code to dynamically update the projection based on the bounding box of the entire feature collection:

       var b = path.bounds( json ),
       s = .95 / Math.max((b[1][0] - b[0][0]) / w, (b[1][1] - b[0][1]) / h),
       t = [(w - s * (b[1][0] + b[0][0])) / 2, (h - s * (b[1][1] + b[0][1])) / 2];
    
       projection
            .scale(s)
            .translate(t);
    

因此,更新后的完整示例将如下所示:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>D3: Setting path fills</title>
        <script type="text/javascript" src="../d3/d3.v3.js"></script>
        <style type="text/css">
            /* No style rules here yet */       
        </style>
    </head>
    <body>
        <script type="text/javascript">

            //Width and height
            var w = 500;
            var h = 300;

            //Define map projection
            var projection = d3.geo.mercator()
                                   .translate([0, 0])
                                   .scale(1);

            //Define path generator
            var path = d3.geo.path()
                             .projection(projection);

            //Create SVG element
            var svg = d3.select("body")
                        .append("svg")
                        .attr("width", w)
                        .attr("height", h);

            //Load in GeoJSON data
            d3.json("indiastates1.json", function(json) {

                // Calculate bounding box transforms for entire collection
                var b = path.bounds( json ),
                s = .95 / Math.max((b[1][0] - b[0][0]) / w, (b[1][1] - b[0][1]) / h),
                t = [(w - s * (b[1][0] + b[0][0])) / 2, (h - s * (b[1][1] + b[0][1])) / 2];

                // Update the projection    
                projection
                  .scale(s)
                  .translate(t);


                //Bind data and create one path per GeoJSON feature
                svg.selectAll("path")
                   .data(json.features)
                   .enter()
                   .append("path")
                   .attr("d", path)
                   .style("fill", "steelblue");

            });

        </script>
    </body>
</html>

它在Firefox中显示空白屏幕且没有错误提示,这正常吗?“indiastates1.json”文件应该放在哪里? - reducing activity
不,这表明它未能找到您的输入并正在运行空内容,或者输入以某种方式损坏,而Javascript正在生成SVG但是该SVG无法呈现。使用开发工具查看SVG输出,并在网络选项卡中查看文件是否已加载。indiastates1.json应替换为实际文件所在位置的路径,但还要检查d3.json的文档,因为自从我写这篇文章以来已经过去了5年(我记不清这是在D3切换到使用fetch和promises之前还是之后)。 - user56reinstatemonica8

0
这个问题是因为美国地图的位置使其居中显示。 您可能已经加载了印度文件,但它可能超出了屏幕范围或非常小,难以看清。 您可以手动进行更正,通过更改比例和中心和平移的值来实现。 但更好的方法是从代码中自动找到比例和平移。
var b = path.bounds(#data#),
                s = .95 / Math.max((b[1][0] - b[0][0]) / width, (b[1][1] - b[0][1]) / height),
                 //scaled the bounding box 
                t = [(width - s * (b[1][0] + b[0][0])) / 2, (height - s * (b[1][1] + b[0][1])) / 2];
// new projection
              projection = d3.geo.mercator()
                             .scale(s).translate(t);
              path = path.projection(projection);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接