title: In Leaflet, how to convert leaflet viewport bounding box in EPSG3857 so I can retrieve data stored in EPSG4326
body: <p>My government supplied mapping data is stored in our database with projection EPSG4326. Because all the data is stored as longitudes and latitudes, this data can be loaded and displayed in leaflet successfully and correctly, even though leaflet itself is defaulted to projection EPSG3857. It's ok to do that, as there is no point switching leaflet over to EPSG4326 as there are no map providers that provide map tiles that are projected for EPSG4326 and I don't want to generate them myself.</p>
  
  <p>There is a lot of data, so I only want to retrieve the data that is within the visible viewport. Leaflet provides me with the getBounds() method to retrieve the longitude and latitude of the visible viewport. Unfortunately, the coordinates it provides me are EPSG3857 coordinates, which means that the data retrieved is distorted around the borders - the difference between 4326 and 3857 means that the curve is wrong. </p>
  
  <p>In the image below, I have passed the longitude and latitude of the bounding box to the database and intersected it with the data. I have drawn the green line to show the problem with using the EPSG3857 coordinates that leaflet has provided me. If the coordinates were EPSG4326, then it would have given me wider coordinates that would have retrieved the data above the green line and within the viewport. </p>
  
  <p>I've currently got a hack where I add a couple of degrees to the longitude and latitude of the bounding box, but I was hoping a better solution exists. Is there a better way to achieve this? Can I somehow translate the bounding box to EPSG4326 without having to switch the whole thing over to EPSG4326, thereby losing the map tiles? </p>
  
  <p><a href="https://i.stack.imgur.com/wbRrq.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/wbRrq.png" alt="Distortion Image"></a></p>
  
  <p><strong>Update:</strong></p>
  
  <p>Here is the code I am using in SQL Server on the back end:</p>
  
  <pre><code>CREATE PROC [core].[GetGeoData]
      @Zoom int,
      @BoundingBox_N decimal(18,14),
      @BoundingBox_S decimal(18,14),
      @BoundingBox_E decimal(18,14),
      @BoundingBox_W decimal(18,14)
  AS
  BEGIN
  
      DECLARE @BoundingBox varchar(200)
      DECLARE @BoundingBoxGeo geography
      SET @BoundingBox = 'POLYGON((' + CAST(@BoundingBox_E as varchar(20)) + ' ' + CAST(@BoundingBox_S as varchar(20)) + ',' + CAST(@BoundingBox_E as varchar(20)) + ' ' + CAST(@BoundingBox_N as varchar(20)) + ',' + CAST(@BoundingBox_W as varchar(20)) + ' ' + CAST(@BoundingBox_N as varchar(20)) + ',' + CAST(@BoundingBox_W as varchar(20)) + ' ' + CAST(@BoundingBox_S as varchar(20)) + ',' + CAST(@BoundingBox_E as varchar(20)) + ' ' + CAST(@BoundingBox_S as varchar(20)) + '))'
      SET @BoundingBoxGeo = geography::STGeomFromText(@BoundingBox, 4326)
  
      SELECT PostalCode, geo.STIntersection(@BoundingBoxGeo) AS geo
      FROM [geo].[AustralianGeoData]  
      WHERE  zoom=@Zoom AND geo.STIntersects(@BoundingBoxGeo)=1
  
  END
  </code></pre>
  
  <p>On the front end, inside my code I am calling:</p>
  
  <pre><code>const mapBounds = map.getBounds();
  const zoom = this.map.getZoom();
  const boundingBoxN = mapBounds.getNorth();
  const boundingBoxS = mapBounds.getSouth();
  const boundingBoxE = mapBounds.getEast();
  const boundingBoxW = mapBounds.getWest();
  this.mapService.getGeoData(zoom, boundingBoxN, boundingBoxS, boundingBoxE, boundingBoxW)
              .subscribe(
              response =&gt; { 
     const geoJson = JSON.parse(row.geoJson);
     this.layers.push(geoJson);
  });
  </code></pre>
  
  <p>which passes the bounding box directly to the back end. map is an L.map instance.</p>