简体   繁体   中英

Create a curved border around a d3 map projection

I have created a world map in d3 using the geoNaturalEarth1() shown here . I used a geojson map of the world with this projection to get the map as shown in the code below. However, this shows the countries floating in space without a border. I'd like to draw a border around the map projection, so that it looks more like a map. The border would be the flat top/bottom, curved sides as shown in the projection image. Is this possible, and how could I go about doing it?

var projection = d3.geoNaturalEarth1()
    .translate([w/2, h/2])
    .scale(247)
    .center([0,0]);

var path = d3.geoPath().projection(projection);

d3.json('map.geojson').then(function(world) {

    svg.selectAll(".emissions_path")
        .data(world.features)
        .enter().append("path")
        .attr('fill', '#fff')
        .attr("d", path)
        .style('stroke', 'black')
        .style('stroke-width', '0.5px');

You can provide geojson with type Sphere to the path generator:

The type Sphere is also supported, which is useful for rendering the outline of the globe; a sphere has no coordinates. ( docs )

This looks like:

var outline = {type:"Sphere"}

And it can be passed directly to the path generator:

 var context = d3.select("canvas").node().getContext("2d"), projection = d3.geoNaturalEarth1() .scale(70) .translate([200,100]) path = d3.geoPath() .context(context) .projection(projection); d3.json("https://unpkg.com/world-atlas@1/world/110m.json", function(error, world) { if (error) throw error; context.beginPath(); context.fillStyle = "lightgreen"; path(topojson.feature(world, world.objects.land)); context.fill(); context.beginPath(); context.strokeStyle = "#ccc"; path({type: "Sphere"}) context.stroke(); });
 <canvas width="500" height="300"></canvas> <script src="https://d3js.org/d3.v4.min.js"></script> <script src="https://unpkg.com/topojson-client@3"></script>


As an aside, there is also d3.geoGraticule , which allows for drawing meridians and parallels at regular intervals:

 var context = d3.select("canvas").node().getContext("2d"), projection = d3.geoNaturalEarth1() .scale(70) .translate([200,100]) path = d3.geoPath() .context(context) .projection(projection); d3.json("https://unpkg.com/world-atlas@1/world/110m.json", function(error, world) { if (error) throw error; context.beginPath(); context.fillStyle = "lightgreen"; path(topojson.feature(world, world.objects.land)); context.fill(); context.beginPath(); context.strokeStyle = "#eee"; path(d3.geoGraticule10()) context.stroke(); context.beginPath(); context.strokeStyle = "#000"; path({type:"Sphere"}) context.stroke(); });
 <canvas width="500" height="300"></canvas> <script src="https://d3js.org/d3.v4.min.js"></script> <script src="https://unpkg.com/topojson-client@3"></script>

Translating the code of Andrew Reid , whom I thank for the explanation, to SVG instead of canvas the code is the following

 var projection = d3.geoNaturalEarth1() .translate([w / 2, h / 2]) .scale(247); var path = d3.geoPath().projection(projection); svg.enter("path") .datum({type: "Sphere"}) .attr("d", path) .style("fill", "none") .style("stroke", "black") .style("stroke-width", 3);

@karots96 solution work for me with some changes

svg.append("path") // append instead of enter
    .datum({type: "Sphere"})
    .attr("d", path)
    .style("fill", "none")
    .style("stroke", "black")
    .style("stroke-width", 3);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM