Create a curved border around a d3 map projection

谁说胖子不能爱 提交于 2021-02-16 19:50:18

问题


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');

回答1:


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>



回答2:


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);


来源:https://stackoverflow.com/questions/54856638/create-a-curved-border-around-a-d3-map-projection

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!