Openlayers XYZ not supporting different tileSizes for the same map instance, 512 and 256

130 views Asked by At
  1. Using OpenLayers ^7.4.0
  2. Trying to get tiles from 2 different providers one gives 256 tileSize images and the other 512
  3. After zoom level 18 or user event, i shift my provider
  4. Using new XYZ to create the source of each tileLayer

Code for reference:

  1. Tile Layer 1 from first source with 512 tilesize
const extent = [12445171.1973, -5518141.946, 17346924.9472, -939258.2036];
    const startResolution = getWidth(extent) / 512;
    const resolutions = new Array(20 + 1);
    resolutions[0] = startResolution;
    for (let i = 1, ii = 20; i <= ii; ++i) {
      resolutions[i] = resolutions[i - 1] / 2;
    }

    const mabBox512Source = new XYZ({
      tilePixelRatio: hiDPI ? 2 : 1,
      tileSize: [512, 512],
      tileGrid: new TileGrid({
        extent: extent,
        resolutions: resolutions,
        tileSize: [512, 512],
      }),
      maxZoom: 20,
      tileUrlFunction: function (tileCoord) {
        const z = tileCoord[0];
        const x = tileCoord[1];
        const y = tileCoord[2];

        const mapBoxURl = `https://api.mapbox.com/style...............`;

        return mapBoxURl;
      },
    });
    
    const tileLayer1 = new OLTileLayer({
      source: mabBox512Source,
      properties: {
        name: 'BASE_TILE_LAYER_1',
      },
    });
  1. Tile Layer 2 from other source with 256 tilesize
    const startResolution2 = getWidth(extent) / 256;
    const resolutions2 = new Array(20 + 1);
    resolutions2[0] = startResolution2;
    for (let i = 1, ii = 20; i <= ii; ++i) {
      resolutions2[i] = resolutions2[i - 1] / 2;
    }

    const newMap256Source = new XYZ({
      tilePixelRatio: hiDPI ? 2 : 1,
      tileSize: [256, 256],
      tileGrid: new TileGrid({
        extent: extent,
        resolutions: resolutions2,
        tileSize: [256, 256],
      }),
      maxZoom: 20,
      tileUrlFunction: function (tileCoord) {
        const z = tileCoord[0];
        const x = tileCoord[1];
        const y = tileCoord[2];

        const nearMapUrl = `https://api.nearmap.com/tiles/.....`;

        return nearMapUrl;
      },
    })
    const tileLayer2 = new OLTileLayer({
      source: newMap256Source,
      properties: {
        name: 'BASE_TILE_LAYER_1',
      },
      visible: false,
    });

And on some condition/userAction in a callback function i am doing the below

      console.log("-----------Switch Layer---------");
      tileLayer1.setVisible(false);
      tileLayer3.setVisible(true);

What is going wrong

I suspect this is not the right way to do it, as the map stops supporting some configuration rules. Like it is not respecting the maxZoom that i had applied. This is a visible breakage. There is a possibility of other breakages which i might not know.

Also, i had tried a different way, where i kept a single tileLayer but i switched the source on user Action/conndition(zoom>18), using setSource. enter image description here

1

There are 1 answers

0
JalajYadav_Avesta On

With help from @Mike , the solution for using two different tileSizes at the same time in the same map instance in openlayers is,

  • You XYZ to create the tileSource
  • Provide different url's with help from tileUrlFunction
  • Also calculate resolutions to provide to the tileGrid option of XYZ.

Read the code snippet below.

const extent = MapService.mapInstance.getView().getProjection().getExtent();
const tileSizes = new Array(20 + 1);
const resolutions = new Array(tileSizes.length);
tileSizes[0] = 512;
resolutions[0] = getWidth(extent) / tileSizes[0];

for (let i = 1, ii = resolutions.length; i < ii; ++i) {
  resolutions[i] = resolutions[i - 1] / 2;
  tileSizes[i] = i < 18 ? 512 : 256;
}

const tileSource1 = new XYZ({
  tilePixelRatio: hiDPI ? 2 : 1,
  tileGrid: new TileGrid({
    extent: extent,
    resolutions: resolutions,
    tileSizes: tileSizes,
  }),
  zDirection: -1,
  tileUrlFunction: function (tileCoord) {
    let z = tileCoord[0];
    const x = tileCoord[1];
    const y = tileCoord[2];
    const tileSize = tileSizes[z];

    z =
      tileSize > tileSizes[0]
        ? z - 1
        : tileSize < tileSizes[0]
          ? z + 1
          : z;

    const map256URL = `https://map_256images_provider/${z}/${x}/${y}.img?until=1Y&tertiary=satellite&apikey=SOMETHING`;

    const map512URL = `https://map_512images_provider/tiles/512/${z}/${x}/${y}${hiDPI ? '@2x' : ''}?access_token=SOMETHING`;

    const url = tileSize === 512 ? map512URL : map256URL;

    return url;
  },
});

const tileLayer1 = new OLTileLayer({
  source: tileSource1,
  properties: {
    name: 'BASE_TILE_LAYER_1',
  },
});

map.addLayer(tileLayer1);