Skip to content

Consuming tiles in Open Layers

Consuming tiles in OpenLayers

The following code can be used to show the generated tile layer in OpenLayers map application.

import TileLayer from "ol/layer/Tile.js";
import WMTS, {optionsFromCapabilities} from 'ol/source/WMTS.js';
import WMTSCapabilities from 'ol/format/WMTSCapabilities.js';

// datasetId is a guid, schemeId is a string that was provided with the request to generate tiles
public static async setupWmtsLayer(datasetId, schemeId) {
  var parser = new WMTSCapabilities();

  // the TileApi class just uses fetch to get the Wmts capabilities document from the endpoint described above
  var capabilities = await TileApi.getTileMetadataWmts(datasetId);

  var parsedCapabilities = parser.read(capabilities)

  var options = optionsFromCapabilities(parsedCapabilities, {
    crossOrigin: "anonymous",
    layer: schemeId // select the correct layer here
  });

  options.tileLoadFunction = tileLoadFunc; // tileLoadFunc is described below

  return new TileLayer({
    isBaseLayer: false,
    noSwitcherDelete: true,
    source: new WMTS(options)
  });
}
The WMTS capabilities document contains urls pointing to Multidimensional service. In order to call this service, you need to provide a valid platform SAS token. Alternatively one can use the Metadata proxy. This way no SAS key management is required from the user, but the url from WMTS capabilities has to be changed so that it points to the Metadata service, and extra headers must be provided (dhi-service-id, dhi-project-id, dhi-dataset-id).

The tileLoadFunction is where we can override various behaviours of loading function that come with Open Layer out of the box. For example, we are able to provide access tokens or open api keys, but also provide values for TIMESTEP and LAYER parameters, or write logic to render data in different formats.One example of such function:

Sample Tile Load Function
options.tileLoadFunction = function tileLoader(imageTile, src) {
  const href = new URL(src);
  href.searchParams.set('TIMESTEP', "2024/05/02T10:00:00.00Z");

  const client = new XMLHttpRequest();
  client.open('GET', href.toString());
  client.responseType = 'arraybuffer';
  client.setRequestHeader("dhi-platorm-api-key", "<fill in actual open api key>");
  client.onload = function () {
    const arrayBufferView = new Uint8Array(this.response);
    const blob = new Blob([arrayBufferView], { type: 'image/webp' });
    const urlCreator = window.URL || window.webkitURL;
    imageTile.getImage().src = urlCreator.createObjectURL(blob);
  };
  client.send();
};

The tiling service generates tiles only to the zoom level where the original data do not have to be resampled to finer resolution. You may need to configure your client for optimal display. In OpenLayers, for example, this means using imageSmoothing: false and also maxZoom: <int> for XYZ source or tileGrid or resolutions parameters for WMTS source. In addition to these parameters, the tiles coordinate system should match the client map coordinate system for best display.

options = {
  crossOrigin: "anonymous",
  layer: "<schema-id-string>",
  imageSmoothing: false
  maxZoom: 4
}

const tileLayer =  new TileLayer({
  isBaseLayer: false,
  noSwitcherDelete: true,
  source: new XYZ(options)
});

Loading map vector tiles into the platform

Sample request to generate tiles
openapikey="<replacewithopenapikey>"

curl -L -X POST "https://api.mike-cloud-test.com/api/conversion/upload-convert" \
  -H 'Content-Type: application/json' \
  -H "dhi-open-api-key: $openapikey" \

  --data-raw "{
  \"projectId\": \"your-project-id\",
  \"uploadUrl\": \"http://sas-url-to-your-zip-archive\",
  \"outputDatasetData\": {
    \"name\": \"dataset-name\"
  },
  \"readerName\": \"FileReader\",
  \"writerName\": \"VectorTilingZipWriter\",
  \"writerParameters\": []
}"

Data source for windy-like components

In order to support visualization components like Windy.com, multiple data sources/variables must be combined into a single raster. Typically the north and east components of wind or current speed are each placed into a single band of the bitmap raster. The tiling mechanism supports this with itemBandMapping property, which allows assigning individual items to bands in the output raster. For example, when using NOAA GFS data, this request will generate XYZ tiles with the "u" and "v" components of the wind speed into one image:

noaa-uv.png

{
  "uploadUrl": "...",
  "outputDatasetData": {
    "name": "noaa-gfs-with-tiles"
  },
  "projectId": "...",

  ### reader parameter is used just to filter out all unrelevant items
  "readerParameters": [
    {
      "name": "AllowedItemNames",
      "value": [
        "u-component of wind @ Tropopause",
        "v-component of wind @ Tropopause"
      ]
    }
  ],

  "writerParameters": [
    {
      "name": "Schemes",
      "value":
        [
          {"schemeType":"XYZ","schemeId":"uv-wind-xyz","outputType":"PNG","aggregationMethod":"Mean","tileWidth":256,"tileHeight":256,
          "itemBandMapping":[
          {"ItemName":"u-component of wind @ Tropopause","MinValue":-62.0,"MaxValue":168.0,"BandIndex":2},
          {"ItemName":"v-component of wind @ Tropopause","MinValue":-73.0,"MaxValue":70.0,"BandIndex":1}]}
          ]
    }
  ],
  "readerName": "NoaaGribReader",
  "writerName": "TilingWriter"
}
BandIndex == 2 actually means the Red channel in the output, 1 indicates Green. Note that this feature has some limitations, e.g. it should be used primarily with the PNG or WEBP output (as it most likely does not make sense to use e.g. binning for this kind of data). Also all the items used within one scheme must have the same data type (which should be true for the use cases such as combining speed components).