如何使用 D3.js 绘制 SVG?

How to make to drawing a SVG with D3.js?

我正在尝试使用我从 API 带来的 GEOJSON 数据在 SVG 中绘制地图,SVG 路径充满了数据,但是,SVG 是空白的,可以执行下面的代码时看到。注意 document.write,数据返回正确。

var svg = d3.select("svg")
d3.json('https://api.mocki.io/v1/d214eb47')
    .then(data => {      
       svg.append('g')
          .selectAll('path')
          .data(data.features)
          .enter()
          .append('path')
          .attr('d', d3.geoPath().projection(d3.geoMercator()))

          document.write(JSON.stringify(data));
    })
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.6.0/d3.min.js"></script>
<svg  width="600" height="600"></svg>

我用另一个 GEOJSON file 对其进行了测试,并成功绘制了 SVG,如下面的代码所示:

const link = "https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/world.geojson";   

var svg = d3.select("svg")

d3.json(link)
        .then(data => {    
         svg.append("g")
        .selectAll("path")
        .data(data.features)
        .enter()
        .append("path")          
          .attr("d", d3.geoPath()
              .projection(d3.geoMercator())
          )
          
         //document.write('data ', JSON.stringify(data))
        
        });
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.6.0/d3.min.js"></script>
<svg width="600" height="600"></svg>

有人知道第一个代码片段有什么问题吗?

数据没有问题,这里的问题只是您试图绘制一个非常小的区域(旧金山)的地图,这与第二个示例中的世界地图不同。也就是说,您应该设置投影的 scalecenter。在你的情况下:

const projection = d3.geoMercator()
    .scale(100000)
    .center([-122.3, 37.75])

结果代码:

var svg = d3.select("svg");
const projection = d3.geoMercator()
  .scale(100000)
  .center([-122.3, 37.75])
d3.json('https://api.mocki.io/v1/d214eb47')
  .then(data => {
    svg.append('g')
      .selectAll('path')
      .data(data.features)
      .enter()
      .append('path')
      .attr('d', d3.geoPath().projection(projection))
  })
path {
  fill: wheat;
  stroke: darkslateblue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.6.0/d3.min.js"></script>
<svg width="600" height="600"></svg>

但是将 fitExtent 与您的 SVG 宽度和高度一起使用会更容易:

const projection = d3.geoMercator()
  .fitExtent([
    [0, 0],
    [600, 600]
  ], data)

这是生成的代码:

var svg = d3.select("svg");
d3.json('https://api.mocki.io/v1/d214eb47')
  .then(data => {
    const projection = d3.geoMercator()
      .fitExtent([
        [0, 0],
        [600, 600]
      ], data)
    svg.append('g')
      .selectAll('path')
      .data(data.features)
      .enter()
      .append('path')
      .attr('d', d3.geoPath().projection(projection))
  })
path {
  fill: wheat;
  stroke: darkslateblue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.6.0/d3.min.js"></script>
<svg width="600" height="600"></svg>

您的 GeoJSON 文件具有非常小的显示区域,但在给定投影和默认 SVG viewBox 中形状几乎为零。

检查我是如何使用您的地理数据找到 SVG G 元素的边界的。然后我用它来定义 SVG viewBox 属性。如果未设置 SVG 宽度或高度,则 SVG 将扩展到可用的“容器”大小。因此,您可以添加周围的 DIV 元素并根据需要设置其大小(将 SVG 安装在您的容器中,从而安装在您的布局中)。

更新:您甚至可以稍后使用 getBBox() 函数的返回值通过 javascript 更改 SVG viewBox 属性。另一个答案中的另一种可能性当然也很好(适合您的 SVG 范围)。

var svg = d3.select("svg");

const link = "https://api.mocki.io/v1/d214eb47";   
//const link = "https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/world.geojson";   

d3.json(link)
    .then(data => {      
    svg.append('g')
      .selectAll('path')
      .data(data.features)
      .enter()
      .append('path')
      .attr('d', d3.geoPath().projection(d3.geoMercator()));

        //console.log(data.features);
        console.log(document.getElementsByTagName("g")[0].getBBox());
  })
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.6.0/d3.min.js"></script>
<svg viewBox="152.95315551757812 140.7493133544922 0.421722412109375 0.4228363037109375"></svg>