Skip to content
Advertisement

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

I’m trying to draw a map in an SVG with the GEOJSON data that I bring from this API, the SVG paths are filled with the data, however, the SVG is blank, as can be seen when executing the code below. Notice the document.write, the data is returned correctly.

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>

I tested it with another GEOJSON file, and managed to draw in SVG as seen when executing the code below:

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>

Does anyone know what’s wrong with the first code snippet?

Advertisement

Answer

There is no issue in the data, the problem here is just that you’re trying to map a very small region (San Francisco), unlike the world map in your second example. That said, you should set the scale and the center of the projection. In your case:

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

The resulting code:

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>

But it’s way easier just using fitExtent with your SVG width and height:

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

And here is the resulting code:

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>
Advertisement