d3 geoPath doesnt draw a great circle

Viewed 34

I want to use d3 to plot some geoJSON on a leaflet map, however, the resultant paths are not being drawn with a great circle. How can I make the d3.geoPath do correct interpolation between points, similar to the standard geographic projections in d3?

Here is my observable snippet

Not a great circle

Versus my old custom map:

Great circle

Observable code:

D3VanAreasMap = {

  let container = DOM.element('div', { style: `width:${width}px;height:${width/1.6}px` });
  
  yield container;
  

  let map = L.map(container).setView([0, 0], 1);
  let osmLayer = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
      attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
  }).addTo(map); 

  let geojson_linestring =  {
       "type": "FeatureCollection",
       "features": [{
           "type": "Feature",
           "geometry": {
               "type": "LineString",
               "coordinates": [
                   [-45, -45],
                   [45, -45],
               ]
           },
           "properties": {}
       }]
  }

  
  //initialize svg to add to map
  L.svg({clickable:true}).addTo(map) // we have to make the svg layer clickable 
  //Create selection using D3
  const overlay = d3.select(map.getPanes().overlayPane)
  const svg = overlay.select('svg').attr("pointer-events", "auto")
  // create a group that is hidden during zooming
  const g = svg.append('g').attr('class', 'leaflet-zoom-hide')
  
  // Use Leaflets projection API for drawing svg path (creates a stream of projected points)
  const projectPoint = function(x, y) {
    const point = map.latLngToLayerPoint(new L.LatLng(y, x))
    this.stream.point(point.x, point.y)
  }
  
  
  // Use d3's custom geo transform method to implement the above
  const projection = d3.geoTransform({point: projectPoint})
  // creates geopath from projected points (SVG)
  const pathCreator = d3.geoPath().projection(projection)
  
  const areaPaths = g.selectAll('path')
    .data(geojson_linestring.features)
    .join('path')
    .attr('fill-opacity', 0.3)
    .attr('stroke', 'black')
    .attr("z-index", 3000)
    .attr('stroke-width', 2.5)
    .on("mouseover", function(d){
                d3.select(this).attr("fill", "red")
            })
    .on("mouseout", function(d){
                d3.select(this).attr("fill", "black")
            })
  
  // Function to place svg based on zoom
  const onZoom = () => areaPaths.attr('d', pathCreator)
  // initialize positioning
  onZoom()
  // reset whenever map is moved
  map.on('zoomend', onZoom)
  
}
0 Answers
Related