Displaying a Basic Interactive Map

An interactive map can be integrated into own apps by making use of the RESTClosed REST (Representational State Transfer) represents a World Wide Web paradigm, consisting of constraints to the design of components which results in a better performance and maintainability. API of PTV xMap in combination with one of multiple available toolkits which takes care of the map layout and user interaction. Usually a tile server like PTV xMap contains and renders tiles for specific coordinates and a zoom level. Then a superior component is needed that must generate the correct HTTP requests to the tile server and, after receiving the tiles, must position them correctly. Of the various alternatives that exist for this job, the popular Leaflet and OpenLayers toolkits are used in the examples below. They demonstrate the correct configuration of PTV xMap for these toolkits, especially for different tile sizes. The tile size should only be increased if high resolution output is demanded, for retina displays on mobile devices or simple printing. Otherwise, rendering the complete map would result in too many tiles.

Benefits

Retrieving tiled maps via the xMap REST API has several advantages over other approaches:

Prerequisites

Check if the following prerequisites are fulfilled before you start with the use case:

  • Installed and licensed PTV xMap Server
  • Installed PTV Map

Concepts

Map tiles are the key concept to this use case. The map that is displayed to the user is not delivered as a single image, but assembled from tiles. The client application requests the tiles needed for the current map view. When the user moves the map, the application only has to load the tiles that come into view, but not the entire map. The default size of a tile is 256x256 pixels.

Each map tile is identified by the following three values:

  • z: zoom level
  • x: horizontal coordinate
  • y: vertical coordinate

These values are also part of the map tile's URL:

http://hostname:50000/services/rest/XMap/tile/{z}/{x}/{y}

Please note the order of the parameters and refer to the REST operation tile to learn more about the supported URL schema. This is the information you must supply to your toolkit to have it display tiles from PTV xMap.

For further details about tile identification see the technical concept page about the Map Tile API.

Programming Guide

The following code samples demonstrate two different use cases:

  • Creation of a map with as few as possible lines of code. Only the fundamental steps and options are shown.
  • Enlarging the tile sizes. This may be needed when too many (256x256) tiles are requested because of a high resolution output medium in use.

In the following chapters both use cases are shown by means of the Leaflet and OpenLayers toolkits.

Leaflet

In the following sample, a Leaflet defined TileLayer is used to address the xMap tiles. Besides the settings of the copyright text and the minimum and maximum zoom ranges, this generated tile layer is added to the map. By means of the URL template, the corresponding tiles are requested to construct the complete map image:

var map = new L.Map('map', { center: [49.61, 6.125], zoom: 13 }); // Add a tile layer with the url pattern. var tileUrl = xServerUrl + '/services/rest/XMap/tile/{z}/{x}/{y}'; new L.TileLayer(tileUrl, { minZoom: 1, maxZoom: 19}).addTo(map);

As displays are now supporting very high resolutions, this means that much more server requests will be required to fill a single map view. For example, on a laptop with retina display, opening a single full screen map may result in about 50 individual tiles being requested simultaneously. This is a problem as by default web browsers will limit the number of active connections for each domain. This value varies per browser, but we're talking about an average of 6 concurrent downloads per domain, which is quite low. So, assuming all tiles are served from the same domain, lots of throttling will occur.

The tile generation process can be manipulated indirectly by specifying deviating layer creation options, so an option will be to generate bigger tiles, for example 512 pixels for width and height, hence reducing the number of requests. But we should get the same geographical content independent from the used tile size. This goal is achieved by rendering the bigger image, which covers multiple tiles in higher zoom levels, with the same concentration used by these higher zoom levels.

xMap supports setting of different sizes for the tiles. At first, the URL template has to be extended: The default values for the profileClosed A profile is a collection of parameters used to configure the request. Full profiles consist of a number of specialized sub-profiles like the VehicleProfile which describes the properties of a vehicle., response content type and the image format have to be considered before the tile size can be specified:

http://hostname:50000/services/rest/XMap/tile/{z}/{x}/{y}?size={tileSize}

The {tileSize} parameter is filled by Leaflet via the optional TileLayer constructor parameter:

var map = new L.Map('map', { center: [49.61, 6.125], zoom: 13 }); // Add a tile layer with the url pattern. var tileSize = 512; var tileUrl = xServerUrl + '/services/rest/XMap/tile/{z}/{x}/{y}?size={tileSize}'; new L.TileLayer(tileUrl, { tileSize: tileSize, zoomOffset: Math.log(256 / tileSize) / Math.log(2), minZoom: 1, maxZoom: 19 }).addTo(map);

Besides the tileSize parameter, filled with the same named variable, the zoomOffset has to be modified. When bigger tiles are requested Leaflet modifies the Tile identification: A doubled tile size results in a bisection of the x- and y- tile IDs. This is corrected by bringing the default size (256 pixels) into correlation with the actual used tile size, see expression used for zoomOffset. As an important side-effect, the tiles will be rendered with the correct zoom level parameter.

This kind of parametrization is specific for xMap as a tile provider service. Services from other organizations may have their own concepts how to interpret the tile sizes, and how a tile size modification influences the geographical extension, effective zoom level and the displayed content of a single map tile. Tiles provided by xMap were modified by the effective zoom level, so the geographical extension remains the same, but the content, especially its concentration of geographical data, will change. The following two tile images demonstrate this, please remark that both URLs differ in the tile size only.

Tiles in default size of 256 x 256 pixels look like this for a Middle European map section:

Tile in standard format with 256 x 256 pixels.
http://hostname:50000/services/rest/XMap/tile/4/8/5?size=256

By changing the tile size to 512 x 512 pixels, the map section remains the same, i.e. the geographical extension is identical. In contrast, the concentration of geographical objects is increased, as can be seen for the displayed towns. Besides the capitals, also medium-sized towns are included:

Tile with 512 x 512 pixels.
http://hostname:50000/services/rest/XMap/tile/4/8/5?size=512

OpenLayers

In the following sample, an OpenLayers defined ol.layer.Tile object is used to address the xMap tiles, which is added to the map. By means of the URL template, the corresponding tiles are requested to construct the complete map image:

var urlTemplate = xServerUrl + '/services/rest/XMap/tile/{z}/{x}/{y}'; var map = new ol.Map({ target: 'map', view: new ol.View({ center: ol.proj.transform([6.125, 49.61], 'EPSG:4326', 'EPSG:3857'), zoom: 13 }) }); // Determine the copyright with a request to xRuntime. function determineCopyright() { var urlPath = xServerUrl + '/services/rest/XRuntime/dataInformation'; $.ajax(urlPath).always(function(response){ if (response) { addTileLayer(response.mapDescription.copyright); } }); }; determineCopyright(); // Add a tile layer with the url pattern. function addTileLayer(copyright) { var xMapLayer = new ol.layer.Tile({ source: new ol.source.XYZ({ url: urlTemplate, attributions: '© ' + new Date().getFullYear() + ' ' + copyright.basemap.join(", ") }) }); map.addLayer(xMapLayer); }

For high resolution use cases, the tile generation process can be manipulated indirectly by specifying bigger tiles, with 512 pixels for width and height. At first, the URL template has to be extended for the new tile sizes. The default values for the profile, response content type and the image format have to be considered before the tile size can be specified:

http://hostname:50000/services/rest/XMap/tile/{z}/{x}/{y}?size={tileSize}

Via the ol.source.XYZ constructor the tile size and a customized URL transformation function, which transforms template parameters to concrete values, can be provided to the OpenLayer layer object, handling correctly the new tile size:

var tileSize = 512; var urlTemplate = xServerUrl + '/services/rest/XMap/tile/{z}/{x}/{y}?size={tileSize}'; var map = new ol.Map({ target: 'map', view: new ol.View({ center: ol.proj.transform([6.125, 49.61], 'EPSG:4326', 'EPSG:3857'), zoom: 13 }) }); // Determine the copyright with a request to xRuntime. function determineCopyright() { var urlPath = xServerUrl + '/services/rest/XRuntime/experimental/dataInformation'; $.ajax(urlPath).always(function(response){ if (response) { addTileLayer(response.mapDescription.copyright); } }); }; determineCopyright(); // Add a tile layer with the url pattern. function addTileLayer(copyright) { var xMapLayer = new ol.layer.Tile({ source: new ol.source.XYZ({ tileSize: tileSize, tileUrlFunction: function(tileCoord) { return urlTemplate.replace('{z}', tileCoord[0].toString()) .replace('{x}', tileCoord[1].toString()) .replace('{y}', (-tileCoord[2] - 1).toString()) .replace('{tileSize}', tileSize.toString()) ; }, attributions: '© ' + new Date().getFullYear() + ' ' + copyright.basemap.join(", ") }) }); map.addLayer(xMapLayer); }

Related Topics

While the xMap REST API is easy to use and sufficient for many applications, it is not quite powerful enough for some more advanced use cases. These are explained on the following pages: