Search code examples
javascriptmapsopenlayersopenlayers-8

Converting map which uses Leaflet.js CRS.Simple to OpenLayers 8.x


I have a game map implemented in Leaflet.js with custom coordinate transformations for Grand Theft Auto V. I'm trying to convert this map from Leaflet.js into Open Layers 8.x due to some annoying limitations in Leaflet.js and the need for some of Open Layers features not easily available within Leaflet.js.

function createCRS() {
  return L.extend({}, L.CRS.Simple, {
    projection: L.Projection.LonLat,
    transformation: new L.Transformation(0.02072, 117.3, -0.0205, 172.8),
    scale: function (zoom) {
      return Math.pow(2, zoom);
    },
    zoom: function (scale) {
      return Math.log(scale) / 0.6931471805599453;
    },
    distance: function (pos1, pos2) {
      var x_difference = pos2.lng - pos1.lng;
      var y_difference = pos2.lat - pos1.lat;
      return Math.sqrt(x_difference * x_difference + y_difference * y_difference);
    },
    infinite: true
  })
}

var crs = createCRS();
var map = new L.Map('map', {
  center: [0, 0],
  zoom: 3,
  crs: crs,
  pmIgnore: false,
});

L.marker([0, 0], {}).addTo(map) // coordinate 0,0

// map layer boilerplate omitted for brevity

It's worth noting that coordinate [0, 0] is not in the top left of the map, it's actually towards the bottom left corner:

map marker 0,0

The Grand Theft Auto V map is 8192 x 8192px in size and I use map tiles (256 x 256px tiles) with up to 5 zoom levels. I've tried to use addCoordinateTransforms and a projection with the pixels unit, but have had no luck. Any markers I add to the map at coordinate [0, 0] always end up at the top-left corner of the map, which in turn means every other valid GTA 5 coordinate is also incorrectly placed (usually off the map).

You can see a reproduction of the incorrect [0, 0] coordinate at the following sandbox, complete with the coordinate plane image outlining where coordinate [0, 0] should be located. My ultimate goal is to do this in a way where I can apply any marker, polygon, etc. as a map layer using GTA V coordinates without having to transform the coordinates while inserting them. Instead, coordinates should be translated properly by whatever transformation layer exists within Open Layers.

Code Sandbox: https://codesandbox.io/p/sandbox/ol-gtavmap-gnkdmf


Solution

  • The leaflet transformation appears to be the offset and scale of the center [0, 0] at zoom 0. OpenLayers does not easily support different x and y axis resolutions, so if I average the scale and calculate the extent for the tilegrid as

    const scale = (0.02072 + 0.0205) / 2;
    const extent = [
      -117.3 / scale,
      (172.8 - 256) / scale,
      (256 - 117.3) / scale,
      172.8 / scale,
    ];
    
    const tileGrid = createXYZ({
      tileSize: 256,
      extent: extent,
      maxZoom: 4,
    });
    

    The view center coordinate [0, 0] is over the [0, 0] intersection https://codesandbox.io/p/sandbox/ol-gtavmap-forked-npjrj2