【问题标题】:Render topoJSON data using D3.js使用 D3.js 渲染 topoJSON 数据
【发布时间】:2021-06-11 11:30:36
【问题描述】:

在我的项目中,我尝试使用 d3 和 GeoJSON 显示印度地图。它不能正常工作,我发现很难显示每个印度州。请帮我找出来,提前谢谢..., 我在代码下方添加了数据和输出的链接。

这是我的源代码,我正在使用来自 https://www.covid19india.org/mini_maps/india.json 的数据,我想使用 D3.js 渲染(印度各州)

<html>

<head>
  <meta charset="utf-8">
  <title>A D3 map using topojson</title>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/queue-async/1.0.7/queue.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/topojson/1.6.19/topojson.min.js"></script>

  <link href="http://fonts.googleapis.com/css?family=Montserrat" rel="stylesheet" type="text/css">
  <style>
    path {
      fill: #ccc;
      stroke: #fff;
      stroke-width: .5px;
    }
    
    path:hover {
      fill: red;
    }
  </style>
</head>

<body>
  <script>
    var width = 900,
      height = 600;

    var path = d3.geo.path();

    var svg = d3.select("body").append("svg")
      .attr("width", width)
      .attr("height", height);

    queue()
      .defer(d3.json, "https://www.covid19india.org/mini_maps/india.json")
      .await(ready);

    function ready(error, counties) {
    svg.append("g")
    .selectAll("path")
    .data(topojson.feature(counties, counties.objects.ele).features)
    .enter()
    .append("path")
    .attr("d", path)
    .attr("class", "state");
    }
  </script>
</body>

</html>

我得到了这种类型的输出

你能帮帮我吗,有什么问题吗?我是一名学生,正在学习这个。

【问题讨论】:

    标签: javascript json d3.js geojson topojson


    【解决方案1】:

    @Gerardo above 提供的答案是针对 D3 v3。

    对于寻找 D3 v6 的任何人,以下是解决方案。

    注意:在 D3 v6 中,d3.geo.path() 已更改为 d3.geoPath()

    // Reference: https://*.com/a/66622694/6908282
    
    var width = 900,
          height = 600;
    
        var path = d3.geoPath()
          .projection(null);
    
        var svg = d3.select("body").append("svg")
          .attr("width", width)
          .attr("height", height);
    
     fetch("https://www.covid19india.org/mini_maps/india.json")
                .then(response => response.json())
                .then(json => {
                    svg.append("g")
                        .selectAll("path")
                        .data(topojson.feature(json, json.objects.states).features)
                        .enter()
                        .append("path")
                        .attr("d", path)
                        .attr("class", "state");
                });
    path {
          fill: #ccc;
          stroke: #fff;
          stroke-width: .5px;
        }
        
        path:hover {
          fill: red;
        }
    <script src="https://d3js.org/d3.v6.min.js"></script>
    <script src="https://unpkg.com/topojson@3"></script>

    【讨论】:

      【解决方案2】:

      由于您的 JSON 已经被投影,您只需将 null 传递给投影:

      var path = d3.geo.path()
          .projection(null);
      

      这是您的更改代码:

      <html>
      
      <head>
        <meta charset="utf-8">
        <title>A D3 map using topojson</title>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/queue-async/1.0.7/queue.min.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/topojson/1.6.19/topojson.min.js"></script>
      
        <link href="http://fonts.googleapis.com/css?family=Montserrat" rel="stylesheet" type="text/css">
        <style>
          path {
            fill: #ccc;
            stroke: #fff;
            stroke-width: .5px;
          }
          
          path:hover {
            fill: red;
          }
        </style>
      </head>
      
      <body>
        <script>
          var width = 900,
            height = 600;
      
          var path = d3.geo.path()
            .projection(null);
      
          var svg = d3.select("body").append("svg")
            .attr("width", width)
            .attr("height", height);
      
          queue()
            .defer(d3.json, "https://www.covid19india.org/mini_maps/india.json")
            .await(ready);
      
          function ready(error, counties) {
      
            svg.append("g")
              .selectAll("path")
              .data(topojson.feature(counties, counties.objects.states).features)
              .enter()
              .append("path")
              .attr("d", path)
              .attr("class", "state");
          }
        </script>
      </body>
      
      </html>

      【讨论】:

      • 非常感谢。这意味着很多
      【解决方案3】:

      您好,我曾经有一个名为 covid19news.org 的网站。现在已经下降了。在那里我做过类似的事情。代码如下。

      <!DOCTYPE html>
      <html>
      <head>
          <meta charset="utf-8">
          <meta name="viewport" content="width=device-width, initial-scale=1">
          <style>
          #map    { position: relative; min-height: 500px;  
             width: 800px;
          height: 770px;
          background-color: white;
      }
      
      .district, .disputed, .state rect, .state path { stroke: #a9a9a9; stroke-width: 1px; }
      
      .district:hover { stroke: #777777; stroke-width: 1px; fill-opacity: .7; }
      .state:hover rect { stroke: #777777; stroke-width: 2px; fill-opacity: .7; }
      .state:hover path { fill-opacity: .7; }
      
      #select {
          position:absolute;
          left: 500px;
          top: 100px;
              font: 12px sans-serif;
              color: #333;
      }
      
      #tooltip h3 {
              margin:2px;
              font-size:14px;
      }
      #tooltip h4 {
              margin:2px;
              font-size:10px;
      }
      #tooltip {
              position: absolute;           
              background:rgba(0,0,0,0.8);
              text-align: left;
              border:1px;
              border-radius:5px;
              font: 12px sans-serif;        
              width:auto;
              padding:4px;
              color:white;
              opacity:0;
              pointer-events: none;         
      }
      #tooltip table{
              table-layout:fixed;
      }
      #tooltip tr td{
              padding:2px;
              margin:0;
      }
      </style>
      </head>
      <body>
              <div id="map">
              </div>
          <script src="./topo/d3.v3.min.js" charset="utf-8"></script>
          <script src="./topo/d3-queue.v3.min.js"></script>
          <script src="./topo/topojson.v1.min.js"></script>
          <script>
          function districtMap(districts, disputed) {
      
      var width  = 800, height = 700, scale = 1200;
      var propTag = 'zone', ttName = 'Zone', unit = '';
      var extraTop = 0, extraLeft = 0;
      function render(selection) {
        selection.each(function() {
      
          d3.select(this).select("svg").remove();
          var svg = d3.select(this).append("svg")
                      .attr("width", width)
                      .attr("height", height);
      
          d3.select(this).select("#tooltip").remove();
          d3.select(this).append("div").attr("id", "tooltip").style("opacity", 1);
      
          var projection = d3.geo.mercator()
              .center([83, 23])
              .scale(scale)
              .translate([width / 2, height / 2]);
      
          var path = d3.geo.path().projection(projection);
      
          svg.selectAll(".district")
              .data(districts.features)
            .enter().append("path")
              .attr("class", "district")
              .style("fill", function(d) { return 'd.properties.zone.toLowerCase();' })
              .attr("d", path)
            .on("mouseover", function(d) {      
                   d3.select("#tooltip").transition()        
                      .duration(200)      
                      .style("opacity", .9);     
                   d3.select("#tooltip").html("<h3>"+(d.id)+"</h3><h4>("+(d.properties.NAME_1)+")</h4><table>"+
                            "<tr><td>"+ttName+"::</td><td>"+(d.properties[propTag])+"</td></tr>"+
                            "</table>")
                      .style("left", (d3.event.pageX-document.getElementById('map').offsetLeft - extraLeft) + "px") 
                      .style("top", (d3.event.pageY-document.getElementById('map').offsetTop - 160 - extraTop) + "px");
            })  
            .on("mouseout", function(d) {       
                   d3.select("#tooltip").transition()        
                      .duration(500)      
                      .style("opacity", 1);   
            });
            
          svg.selectAll(".disputed")
              .data(disputed.features)
            .enter().append("path")
              .attr("class", "disputed")
              .style("fill", function(d) { return d.color; })
              .attr("d", path);
      
        });
      } // render
      render.height = function(value) {
                  if (!arguments.length) return height;
                  height = value;
                  return render;
              };
      render.width = function(value) {
                  if (!arguments.length) return width;
                  width = value;
                  return render;
              };
      render.scale = function(value) {
                  if (!arguments.length) return scale;
                  scale = value;
                  return render;
              };
      render.propTag = function(value) {
                  if (!arguments.length) return propTag;
                  propTag = value;
                  return render;
              };
      render.ttName = function(value) {
                  if (!arguments.length) return ttName;
                  ttName = value;
                  return render;
              };
      render.unit = function(value) {
                  if (!arguments.length) return unit;
                  unit = value;
                  return render;
              };
      
      return render;
      } // districtMap
          (function() {
          d3.queue()
              .defer(d3.json, "./topo/zone-data.json")
              .defer(d3.json, "./topo/Kashmir.json")
              .await(function(error, topoMain, topoKashmir) {
                  var districts, disputed;
                  if (error) throw error;
                  districts   = topojson.feature(topoMain, topoMain.objects.IND_adm2);
                  disputed    = topojson.feature(topoKashmir, topoKashmir.objects.ne_10m_admin_0_Kashmir_Occupied);
                  colorDisputed(disputed.features);
      
                  // Map render
                  var map     = districtMap(districts, disputed).width(800).height(700).scale(1200); //.propTag(filter);
                
                  d3.select("#map").call(map);
             
              });
      }());
                
      
      function colorDisputed(data) {
          var color         = "#eaeafa";
          data.forEach(function(d) { 
              d.color       = color;
          });
      }
          </script>
      </body>
      </html>
      

      完整的工作代码在这里。 stackblitz

      【讨论】:

      • 非常感谢您的支持
      • 如果您认为它有帮助,请接受此答案