0

I want to create a custom tile that is a perfect fit on a certain extent. For example, I want to be able to map it on the map at exact spots of an Open Source Map. I saw this example, but it does not explain how the tiles are made and how to make it such that it fits the extent perfectly. The example below puts custom layer at an extent, I want to know how to create such tiles. I am using XYZ source for my code. Example was taken from :

https://openlayers.org/en/latest/examples/arcgis-tiled.html

<!DOCTYPE html>
<html>
  <head>
    <title>Tiled ArcGIS MapServer</title>
    <link rel="stylesheet" href="https://openlayers.org/en/v5.3.0/css/ol.css" type="text/css">
    <!-- The line below is only needed for old environments like Internet Explorer and Android 4.x -->
    <script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=requestAnimationFrame,Element.prototype.classList,URL"></script>

  </head>
  <body>
    <div id="map" class="map"></div>
    <script>
      import Map from 'ol/Map.js';
      import View from 'ol/View.js';
      import TileLayer from 'ol/layer/Tile.js';
      import {OSM, TileArcGISRest} from 'ol/source.js';

      var url = 'https://sampleserver1.arcgisonline.com/ArcGIS/rest/services/' +
          'Specialty/ESRI_StateCityHighway_USA/MapServer';

      var layers = [
        new TileLayer({
          source: new OSM()
        }),
        new TileLayer({
          extent: [-13884991, 2870341, -7455066, 6338219],
          source: new TileArcGISRest({
            url: url
          })
        })
      ];
      var map = new Map({
        layers: layers,
        target: 'map',
        view: new View({
          center: [-10997148, 4569099],
          zoom: 4
        })
      });
    </script>
  </body>
</html>
Ashim
  • 877
  • 2
  • 12
  • 22

1 Answers1

0

In that example the tiles use a standard EPSG:3857 grid, the same as the OSM layer. The extent has been set to limit requests to a specific area (USA including Hawaii and most of Alaska - but not the western end of the Aleutians). At zoom level zero the single tile covers the world (transparent shows as black):

enter image description here

If you set the same extent on the OSM layer you would also restrict the area displayed, but it wouldn't affect the tiles. With global projections it is normal to stick to a standard grid and restrict the layer extent to avoid requests to areas where you don't have tiles. In other projections you can create you own grid, and specify that in OpenLayers using the source's tileGrid option to match what you created.

Here's an example of how to set up a custom tile grid for https://server.arcgisonline.com/ArcGIS/rest/services/Polar/Antarctic_Imagery/MapServer

// define polar projection

proj4.defs("EPSG:3031", "+proj=stere +lat_0=-90 +lat_ts=-71 +lon_0=0 +k=1 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs");
ol.proj.proj4.register(proj4);

// redefine transforms to catch errors

var inverse = ol.proj.getTransform('EPSG:3031', 'EPSG:3857');
var forward = ol.proj.getTransform('EPSG:3857', 'EPSG:3031');

ol.proj.addCoordinateTransforms(
  'EPSG:3857',
  'EPSG:3031',
  function(coordinate) {
    try {
      return forward(coordinate)
    } catch (e) {
      return [undefined, undefined]
    }
  },
  function(coordinate) {
    try {
      return inverse(coordinate)
    } catch (e) {
      return [undefined, undefined]
    }
  }
);

var baseMapLayer = new ol.layer.Tile({
  source: new ol.source.XYZ({
    url: 'https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}',
    maxZoom: 23
  })
});

var extent = [-3.369955099203E7, -3.369955099203E7, 3.369955099203E7, 3.369955099203E7];
var maxResolution = 238810.81335399998;

var resolutions = [];
for (var i = 0; i < 24; i++) {
  resolutions[i] = maxResolution / Math.pow(2, i);
}

var esriArctic = new ol.layer.Tile({
  source: new ol.source.XYZ({
    url: 'https://services.arcgisonline.com/arcgis/rest/services/Polar/Antarctic_Imagery/MapServer/tile/{z}/{y}/{x}',
    projection: 'EPSG:3031',
    tileGrid: new ol.tilegrid.TileGrid({ extent: extent, resolutions: resolutions })
  })
});

// create a "layer spy" around the pole

esriArctic.on('precompose', function(event) {
  radius = 4000000 / event.frameState.viewState.resolution;
  var ctx = event.context;
  var pixelRatio = event.frameState.pixelRatio;
  ctx.save();
  ctx.beginPath();
  position = map.getPixelFromCoordinate(ol.proj.fromLonLat([0, -90], 'EPSG:3031'));
  // only show a circle around the position
  ctx.arc(position[0] * pixelRatio, position[1] * pixelRatio, radius * pixelRatio, 0, 2 * Math.PI);
  ctx.clip();
});

// after rendering the layer, restore the canvas context
esriArctic.on('postcompose', function(event) {
  var ctx = event.context;
  ctx.restore();
});

var map = new ol.Map({
  target: 'map',
  layers: [baseMapLayer, esriArctic],
  view: new ol.View({
    projection: 'EPSG:3031',
    center: ol.proj.fromLonLat([0, -80], 'EPSG:3031'),
    zoom: 3
  })
});
   html,
   body,
   #map {
     width: 100%;
     height: 100%;
     overflow: hidden;
   }
<script src="https://cdnjs.cloudflare.com/ajax/libs/proj4js/2.5.0/proj4.js"></script>
<link href="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/css/ol.css" rel="stylesheet"/>
<script src="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/build/ol.js"></script>
<body>
  <div id="map" class="map"></div>
</body>
Mike
  • 16,042
  • 2
  • 14
  • 30
  • Thank you for your comment. Basically what i have is PNG files which act as tiles source for XYZ. I want to put these custom tiles in a way that it is overlays with the world map which is in EPSG: 4326 projection. How do i do this ? – Ashim Aug 02 '19 at 09:19
  • You will need to know the coordinates of the tiles (the extent of each level zoom and the number of rows and columns is sufficient), then you can define a tile grid in OpenLayers. – Mike Aug 02 '19 at 09:43
  • could you provide me an online example if you have. Thanks – Ashim Aug 05 '19 at 06:42