Search code examples
javascriptd3.jsgeojsontopojson

Why does Svg path appears in console but not on screen?


I was wondering if anyone could lend me a hand.

I'm trying to render a map of Singapore from the following topoJSON which I had converted.

Below is my code:

<style>
    path {
        /*fill: #ccc;*/
        stroke: rgba(12, 12, 12, 0.96);
        stroke-linejoin: round;
    }
</style>
    <svg width="900" height="600"></svg>

<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://d3js.org/topojson.v2.min.js"></script>
<script>
     var svg = d3.select("svg"),
         width = +svg.attr("width"),
         height = +svg.attr("height");

//     var projection = d3.geoAlbers();
     var projection = d3.geoMercator()
         .center([0, 5 ])
         .scale(900)
         .rotate([-180,0]);

     var path = d3.geoPath(projection);

    d3.queue()
        .defer(d3.json, "data/sgtopo.json")
        .await(ready);

    function ready(error, sg){
        if(error) throw error;
        var topofeature = topojson.feature(sg, sg.objects["sg-"]);
        svg.append("g")
         .selectAll("path")
         .data(topofeature.features)
         .enter()
         .append("path")
         .attr("d", path);


    }
</script>
</html>

While i see the path generated on the console: the page remains blank. Would appreciate any help please thank you!

enter image description here

enter image description here


Solution

  • As noted in the other answer's comments, the drawing takes place off the screen. This is a common problem with troubleshooting d3.js maps: no errors are thrown but no data is visibly drawn. When this is the case, usually the issue is you have chosen incorrect projection parameters.

    If I substitute your topojson for a world json this is my result:

    enter image description here

    It is centered at 180 degrees east/west and five degrees north. This is centered in the Pacific, east of Indonesia. Singapore, however, is at ~104 degrees east and ~1 degree north. So your projection parameters should be more like:

         var projection = d3.geoMercator()
         .center([103.833333, 1.283333 ])
         .scale(900)
    

    In fact, your scale could be much larger, in order to zoom in further. With a scale of 900 and the center specified above, I get something like this:

    enter image description here

    Using

         var projection = d3.geoMercator()
         .center([103.833333, 1.283333 ])
         .scale(60000)
    

    and your data (and code from above), I got something like:

    enter image description here

    Also, with a Mercator projection, you do not need to use rotate as the map is properly aligned no matter where you center it (unlike with, say, conical projections). Simply centering it on the coordinate that is at the center of your feature is sufficient.