'OpenLayers - TileArcGISRest vs. XYZ
OpenLayers docs on TileArcGISRest says:
For cached ArcGIS services, better performance is available by using ol/source/XYZ instead.
But XYZ is not adapted to ArcGis and my ArcGis tile map (with Single Fused Map Cache) does not fit OSM when using XYZ (see screenshot). Only TileArcGISRest in my code makes the map layer fit the OSM layer. That leaves me with some questions:
- How do I migrate TileArcGISRest to XYZ?
- Why does XYZ perform better?
- Why doesn't TileArcGISRest implement performance improvements accordingly?
My code is as follows:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.13.0/css/ol.css"
type="text/css"
/>
<style>
.map {
height: 95vh;
width: 100%;
}
</style>
<script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.13.0/build/ol.js"></script>
<title>OpenLayers example</title>
</head>
<body>
<div id="map" class="map"></div>
<script type="text/javascript">
const host = "map_host";
const map = new ol.Map({
target: "map",
layers: [
// OpenStreetMap layer
new ol.layer.Tile({
source: new ol.source.OSM(),
}),
new ol.layer.Tile({
source: new ol.source.TileArcGISRest({
url: `https://${host}/arcgis/rest/services/Geocache_UTM33_EUREF89/GeocacheBilder/MapServer`,
}),
}),
new ol.layer.Tile({
source: new ol.source.XYZ({
url: `https://${host}/arcgis/rest/services/Geocache_UTM33_EUREF89/GeocacheBilder/MapServer/tile/{z}/{y}/{x}`,
}),
}),
],
view: new ol.View({
center: [0, 6000000],
zoom: 3,
}),
});
</script>
</body>
</html>
Solution 1:[1]
If you obtain the tilegrid from the service json for the cached tiles you can specify the correct OpenLayers XYZ source for the tiles. As the source is in a UTM projection (for which OpenLayers needs proj4) you must either reproject it to web mercator the same as OSM, or specify UTM33 as the view projection and reproject the OSM background.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.13.0/css/ol.css"
type="text/css"
/>
<style>
.map {
height: 95vh;
width: 100%;
}
</style>
<script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.13.0/build/ol.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/proj4js/2.7.5/proj4.js"></script>
<title>OpenLayers example</title>
</head>
<body>
<div id="map" class="map"></div>
<script type="text/javascript">
proj4.defs("EPSG:25833","+proj=utm +zone=33 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs");
ol.proj.proj4.register(proj4);
const map = new ol.Map({
target: "map",
layers: [
// OpenStreetMap layer
new ol.layer.Tile({
source: new ol.source.OSM(),
}),
],
view: new ol.View({
center: [0, 9000000],
zoom: 3,
}),
});
const host = "services.geodataonline.no";
fetch(
`https://${host}/arcgis/rest/services/Geocache_UTM33_EUREF89/GeocacheBilder/MapServer?f=json`
).then(function(response) {
return response.json();
}).then(function(serviceJson) {
const extent = [
serviceJson.fullExtent.xmin,
serviceJson.fullExtent.ymin,
serviceJson.fullExtent.xmax,
serviceJson.fullExtent.ymax,
];
const origin = [
serviceJson.tileInfo.origin.x,
serviceJson.tileInfo.origin.y,
];
const resolutions = serviceJson.tileInfo.lods.map(function(l) { return l.resolution; });
const tileSize = [serviceJson.tileInfo.cols, serviceJson.tileInfo.rows];
const wkid = serviceJson.tileInfo.spatialReference.latestWkid;
const tileGrid = new ol.tilegrid.TileGrid({
extent: extent,
origin: origin,
resolutions: resolutions,
tileSize: tileSize,
});
map.addLayer(
new ol.layer.Tile({
source: new ol.source.XYZ({
url: `https://${host}/arcgis/rest/services/Geocache_UTM33_EUREF89/GeocacheBilder/MapServer/tile/{z}/{y}/{x}`,
tileGrid: tileGrid,
projection: 'EPSG:' + wkid,
}),
})
);
})
</script>
</body>
</html>
Solution 2:[2]
The answer of Mike is correct you have to specify the correct tilegrid to use an ol.source.XYZ.
But I will answers to your 2 questions:
Why does XYZ perform better?
Using an ol.source.XYZ you access the tiles directly, tiles are already generated and stored somewhere on your tile server. No treatment needed by the server. It just send back the tile so requests are faster. Example of a request XYZ request:
https://sampleserver1.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer/tile/8/90/45
Why doesn't TileArcGISRest implement performance improvements accordingly?
Using a TileArcGISRest source. Tiles are created on the fly with the parameter you give (projection, bbox, wisth,height ..). So more backend treatment are needed compared to XYZ. Example of a request :
https://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Specialty/ESRI_StateCityHighway_USA/MapServer/export?
F=image
&FORMAT=PNG32
&TRANSPARENT=true
&SIZE=256%2C256
&BBOX=-13149614.849955441%2C4383204.9499851465%2C-12523442.714243278%2C5009377.08569731
&BBOXSR=3857
&IMAGESR=3857
&DPI=90
To summarize, XYZ use cached tile and TileArcGISRest generates tiles on the fly.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Mike |
| Solution 2 | oterral |

