Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
189 changes: 185 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,198 @@

This document explains the Maps Extension to the [SpatioTemporal Asset Catalog](https://github.com/radiantearth/stac-spec) (STAC) specification.

It describes maps that combine several layers into a single view.
A map combines several layers into a single view with a projection and a default extent.
The layers can come from assets, web map links or renders,
and a stylesheet or a render can be applied to the data of an asset or a service.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A render always references its own data (assets is required in the Render Extension), so it is a layer source on its own and can't also be applied as a style to another asset or service.

Suggested change
and a stylesheet or a render can be applied to the data of an asset or a service.
and a stylesheet can be applied to the data of an asset or a service.

Multiple maps can be provided, e.g. to offer different visualizations of the same data.

This extension doesn't depend on other extensions.
It uses the web map links of the [Web Map Links Extension](https://github.com/stac-extensions/web-map-links)
and the renders of the [Render Extension](https://github.com/stac-extensions/render) if a document provides them.

- Examples:
- [Item example](examples/item.json): Shows the basic usage of the extension in a STAC Item
- [Collection example](examples/collection.json): Shows the basic usage of the extension in a STAC Collection
- [Item example](examples/item.json): Shows maps that combine assets, web map links, renders and stylesheets in a STAC Item
- [Collection example](examples/collection.json): Shows a map with a basemap and a web map link in a STAC Collection
- [JSON Schema](json-schema/schema.json)
- [Changelog](./CHANGELOG.md)

## Fields

The fields of this extension are yet to be defined.
The fields in the table below can be used in these parts of STAC documents:

- [x] Catalogs
- [x] Collections
- [x] Item Properties
- [ ] Assets (for both Collections and Items, incl. Item Asset Definitions in Collections and Asset Templates)
- [x] Links (incl. Link Templates), only [`id`](#link-identifiers)
- [ ] Bands

| Field Name | Type | Description |
| ---------- | ---------------------------------------- | ----------- |
| maps | Map\<string, [Map Object](#map-object)> | **REQUIRED**. Named maps. The keys SHOULD match `^[A-Za-z0-9_-]+$`. |

In Catalogs and Collections, `maps` is a top-level field. In Items, it's part of the `properties`.

### Map Object

| Field Name | Type | Description |
| ------------- | ----------------------------------- | ----------- |
| title | string | A title for the map, e.g. for a map picker. |
| description | string | A description of the map. [CommonMark 0.29](https://commonmark.org/) syntax MAY be used for rich text representation. |
| roles | \[string] | `default` marks the map that clients show by default. |

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nothing prevents several maps from having the default role. Maps are an object, so there's no reliable "first" to fall back on either.

Suggested change
| roles | \[string] | `default` marks the map that clients show by default. |
| roles | \[string] | `default` marks the map that clients show by default. At most one map SHOULD have this role. If none has it, clients choose one. |

| proj:code | string\|null | The projection of the map, as defined in the [Projection Extension](https://github.com/stac-extensions/projection). |
| proj:wkt2 | string\|null | The projection of the map, as defined in the [Projection Extension](https://github.com/stac-extensions/projection). |
| proj:projjson | object\|null | The projection of the map, as defined in the [Projection Extension](https://github.com/stac-extensions/projection). |
| bbox | \[number] | The default extent of the map in WGS 84 (EPSG:4326), with 4 or 6 numbers as for the `bbox` of Items. |
| dimensions | Map\<string, \*> | Default values for the non-spatial dimensions of all layers (e.g. a common `time`). |
| layers | \[[Layer Object](#layer-object)] | **REQUIRED**. The layers of the map, from bottom to top. Can't be empty. |

If no projection is provided, clients choose one, e.g. Web Mercator.
If multiple projection fields are provided, they MUST describe the same projection.

If no `bbox` is provided, clients use the spatial extent of the STAC entity.

**dimensions**: The keys are the names of the dimensions, as used in the [Datacube Extension](https://github.com/stac-extensions/datacube)
(`cube:dimensions`) or by the services (e.g. `TIME` in WMS). The values apply wherever a layer's source doesn't set its own value.
Comment on lines +63 to +64

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If a map mixes a datacube asset (time) and a WMS (TIME), which key applies, and is matching case-sensitive? Keys should always be cube:dimensions names and clients map them to service parameters (WMS TIME/ELEVATION, WMTS dimension identifiers).

This also relates to stac-extensions/render#19 (fixing non-spatial dimensions of a datacube).


### Layer Object

A layer has exactly one **source** and optionally a **style**.

| Field Name | Type | Description |
| -------------- | ------------------------------------------------------------- | ----------- |
| asset | string | Source: The key of an asset. |
| link | string\|Link Object\|Link Template Object | Source: The [`id`](#link-identifiers) of a link or link template in the document, or an embedded link for layers from outside of the document (e.g. a basemap). |
| render | string | Source: The key of a render. The render provides its own data and portrayal. |
| style | [Style Reference Object](#style-reference-object) | The portrayal that is applied to the data of an `asset` or `link` source. |

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
| style | [Style Reference Object](#style-reference-object) | The portrayal that is applied to the data of an `asset` or `link` source. |
| style | [Style Reference Object](#style-reference-object) | The stylesheet that is applied to the data of an `asset` or `link` source. |

| title | string | A title for the layer, e.g. for a layer switcher. Overrides the title of the source. |
| opacity | number | The opacity of the layer, between 0 (transparent) and 1 (opaque). Defaults to `1`. |
| visible | boolean | Whether the layer is visible when the map loads. Defaults to `true`. |
| min_resolution | number | The finest resolution at which the layer is shown, see [resolution ranges](#resolution-ranges). |
| max_resolution | number | The coarsest resolution at which the layer is shown, see [resolution ranges](#resolution-ranges). |

Each layer MUST provide exactly one of `asset`, `link` and `render`.
The keys and `id`s are looked up in the document first and then in the parent Collection.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Say how the parent is found, and that it only applies to Items.

Suggested change
The keys and `id`s are looked up in the document first and then in the parent Collection.
The keys and `id`s are looked up in the document first and then, for Items, in the parent Collection (found through the `collection` link).

For example, an Item can use a render that its Collection defines for the corresponding `item_assets`.

**link**: Web map links from the document are referenced by their `id`, which avoids duplicating them.
Embedding a link is meant for layers that are not part of the document, e.g. a basemap from a third party.
Embedded links follow the definitions of the web map link in use,
e.g. from the [Web Map Links Extension](https://github.com/stac-extensions/web-map-links).

**style**:

- It MUST NOT be provided for a `render` source, as a render has its own portrayal.
- For a `link` source, it can only be provided for services that deliver data instead of images,
e.g. vector tiles through XYZ, TileJSON or PMTiles.

**min_resolution** and **max_resolution**: If the source of the layer is a link that indicates a resolution range itself,
clients only show the layer where both ranges allow it.

### Style Reference Object

| Field Name | Type | Description |
| ---------- | ------------------- | ----------- |
| link | string\|Link Object | The `id` of a stylesheet link in the document, or an embedded stylesheet link. |
| render | string | The key of a render that is applied to the data of the layer's source. |

Each Style Reference Object MUST provide exactly one of `link` and `render`.

**link**: Stylesheet links use the relation type `stylesheet`, which is
[registered by IANA](https://www.iana.org/assignments/link-relations/link-relations.xhtml).
The `type` is REQUIRED and identifies the encoding of the stylesheet, preferably with the media types of
[OGC API - Styles](https://docs.ogc.org/DRAFTS/20-009.html), e.g. `application/vnd.mapbox.style+json` or `application/vnd.ogc.sld+xml`.

**render**: Only renders that don't reference any data themselves can be applied to another source.
Comment on lines +102 to +114

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keep render as a source only. A render always references its own data (assets is required in the Render Extension v2.1.0), so a render without data isn't valid, and using it as a style would mean its assets are silently replaced by the layer's source. Either an asset (optionally with a stylesheet) or a render, not both.

Suggested change
| Field Name | Type | Description |
| ---------- | ------------------- | ----------- |
| link | string\|Link Object | The `id` of a stylesheet link in the document, or an embedded stylesheet link. |
| render | string | The key of a render that is applied to the data of the layer's source. |
Each Style Reference Object MUST provide exactly one of `link` and `render`.
**link**: Stylesheet links use the relation type `stylesheet`, which is
[registered by IANA](https://www.iana.org/assignments/link-relations/link-relations.xhtml).
The `type` is REQUIRED and identifies the encoding of the stylesheet, preferably with the media types of
[OGC API - Styles](https://docs.ogc.org/DRAFTS/20-009.html), e.g. `application/vnd.mapbox.style+json` or `application/vnd.ogc.sld+xml`.
**render**: Only renders that don't reference any data themselves can be applied to another source.
| Field Name | Type | Description |
| ---------- | ------------------- | ----------- |
| link | string\|Link Object | **REQUIRED**. The `id` of a stylesheet link in the document, or an embedded stylesheet link. |
**link**: Stylesheet links use the relation type `stylesheet`, which is
[registered by IANA](https://www.iana.org/assignments/link-relations/link-relations.xhtml).
The `type` is REQUIRED and identifies the encoding of the stylesheet, preferably with the media types of
[OGC API - Styles](https://docs.ogc.org/DRAFTS/20-009.html), e.g. `application/vnd.mapbox.style+json` or `application/vnd.ogc.sld+xml`.
A render can't be used as a style. It always references its own data and is used as a layer source instead,
see `render` in the [Layer Object](#layer-object).


### Possible combinations

The following table shows the possible combinations of sources and styles:

| Layer | Shows |
| ----------------------------------------------------------------- | ----- |
| `{"asset": "visual"}` | The asset with the default portrayal of the client, e.g. an RGB image or a default vector style. |
| `{"asset": "fields", "style": {"link": "fields-outline"}}` | The asset, styled by a stylesheet. |
| `{"asset": "fields", "style": {"render": "fields"}}` | The asset, styled by a render. |
| `{"render": "ndvi"}` | A render with its own data, rendered by the client or delivered by a web map link that references the render. |
| `{"link": "topo-wms"}` | A service as it's delivered. |
| `{"link": "fields-pmtiles", "style": {"link": "fields-outline"}}` | The data of a service, styled by a stylesheet. |
| `{"link": "fields-pmtiles", "style": {"render": "fields"}}` | The data of a service, styled by a render. |
Comment on lines +124 to +128

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Drop the two render-as-style rows, following the change to the Style Reference Object.

Suggested change
| `{"asset": "fields", "style": {"render": "fields"}}` | The asset, styled by a render. |
| `{"render": "ndvi"}` | A render with its own data, rendered by the client or delivered by a web map link that references the render. |
| `{"link": "topo-wms"}` | A service as it's delivered. |
| `{"link": "fields-pmtiles", "style": {"link": "fields-outline"}}` | The data of a service, styled by a stylesheet. |
| `{"link": "fields-pmtiles", "style": {"render": "fields"}}` | The data of a service, styled by a render. |
| `{"render": "ndvi"}` | A render with its own data, rendered by the client or delivered by a web map link that references the render. |
| `{"link": "topo-wms"}` | A service as it's delivered. |
| `{"link": "fields-pmtiles", "style": {"link": "fields-outline"}}` | The data of a service, styled by a stylesheet. |

| `{"link": {"rel": "xyz", "href": "…"}}` | A layer from outside of the document. |

### Resolving layers

Clients resolve each layer as follows:

1. `asset`: Read the asset. Apply the `style` if provided, otherwise use the default portrayal of the client.
2. `link`: Load the service. Apply the `style` to its data if provided.
3. `render`: If the client supports the render and can read its data, render it on the client.
Otherwise, use a web map link that indicates that it delivers the render (e.g. through the field `render`)
and that the client supports. If multiple links match, they are equivalent and the client can choose any of them.
4. If none of the above works, skip the layer and inform the user.

Clients that don't support this extension usually fall back to showing the assets, renders or web map links directly.

### Resolution ranges

`min_resolution` and `max_resolution` define the range of resolutions in which a layer is shown.
Clients SHOULD hide the layer outside of this range.
If both are provided, `min_resolution` must be lower than or equal to `max_resolution`.
Comment on lines +147 to +148

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worth stating the bounds explicitly. OpenLayers uses minResolution inclusive and maxResolution exclusive; matching it avoids clients disagreeing at exactly the boundary.

Suggested change
Clients SHOULD hide the layer outside of this range.
If both are provided, `min_resolution` must be lower than or equal to `max_resolution`.
Clients SHOULD hide the layer outside of this range.
`min_resolution` is inclusive and `max_resolution` is exclusive, i.e. the layer is shown if
`min_resolution <= resolution < max_resolution`, as in OpenLayers.
If both are provided, `min_resolution` must be lower than `max_resolution`.


The resolution is the **distance on the ground in meters per display (CSS) pixel**, measured at the center of the
spatial extent of the STAC entity (`bbox` in Items, the first bounding box of the spatial extent in Collections).
This makes the value independent of the projection of the map.
Comment on lines +150 to +152

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A map can have its own bbox. For a Collection with a global extent and a regional map, measuring at the entity's centre would convert at (0,0) instead of the region.

Suggested change
The resolution is the **distance on the ground in meters per display (CSS) pixel**, measured at the center of the
spatial extent of the STAC entity (`bbox` in Items, the first bounding box of the spatial extent in Collections).
This makes the value independent of the projection of the map.
The resolution is the **distance on the ground in meters per display (CSS) pixel**, measured at the center of the
map's `bbox` if provided, otherwise of the spatial extent of the STAC entity
(`bbox` in Items, the first bounding box of the spatial extent in Collections).
This makes the value independent of the projection of the map.

Clients convert the value into the units of the map projection, e.g. with `getPointResolution` in OpenLayers.

For example, a `max_resolution` of `1000` for data centered at 48° North converts to:

| Map projection | Resolution in map units |
| ------------------------- | ----------------------- |
| EPSG:25832 (UTM zone 32N) | ≈ 1000 m per pixel |
| EPSG:3857 (Web Mercator) | ≈ 1000 / cos(48°) ≈ 1494 m per pixel |
| EPSG:4326 (WGS 84) | ≈ 0.0134° per pixel horizontally, ≈ 0.0090° per pixel vertically |

The ground resolution varies over large extents, so the range is approximate far from the center.
Clients MAY evaluate it at the center of the current view instead,
which is also the fallback for Catalogs and other cases where no spatial extent is available.

The data-side counterpart is `raster:spatial_resolution` of the [Raster Extension](https://github.com/stac-extensions/raster),
which is also measured in meters on the ground.
For example, a layer with categorical data may set its `min_resolution` to the `raster:spatial_resolution`
so that it's not shown beyond the resolution of the data.
`gsd` is not suitable to derive the range as it describes the sensor, not the pixels of the data.

## Link identifiers

This extension adds the following field to the
[Link Object](https://github.com/radiantearth/stac-spec/tree/master/commons/links.md#link-object)
and the Link Template Object of the [Link Templates Extension](https://github.com/stac-extensions/link-templates):

| Field Name | Type | Description |
| ---------- | ------ | ----------- |
| id | string | An identifier for the link, which MUST be unique across all `links` and `linkTemplates` of the document. **REQUIRED** for links that are referenced by a map. |

Links are never referenced by their position in the array,
as the order can change, e.g. when a STAC API adds or regenerates links such as `self`, `root` or `parent`.

## Relation to other specifications

- [Render Extension](https://github.com/stac-extensions/render):
A render describes how data is portrayed. A map decides which renders are shown together, and where.
Visibility ranges are therefore defined for the map layers, not for renders.
- [Web Map Links Extension](https://github.com/stac-extensions/web-map-links):
Web map links describe services. A map references them as layers by their `id`.
A web map link can indicate that it delivers a render (e.g. through the field `render`),
so that clients can choose between rendering on the client and using the service.
- [Link Templates Extension](https://github.com/stac-extensions/link-templates):
Link templates are referenced by their `id` like links.
- [Projection Extension](https://github.com/stac-extensions/projection):
The fields `proj:code`, `proj:wkt2` and `proj:projjson` are used to define the projection of a map.
- [OGC API - Maps](https://docs.ogc.org/DRAFTS/20-058.html):
The map resources of OGC API - Maps (e.g. `/map` and `/styles/{styleId}/map`) are services that deliver images.
They are described as web map links and can be used as layers in the maps of this extension.
- [OGC API - Styles](https://docs.ogc.org/DRAFTS/20-009.html):
Stylesheet links follow OGC API - Styles, i.e. the relation type `stylesheet` and the media types for the encodings.

## Contributing

Expand Down
55 changes: 45 additions & 10 deletions examples/collection.json
Original file line number Diff line number Diff line change
@@ -1,33 +1,60 @@
{
"stac_version": "1.1.0",
"stac_extensions": [
"https://stac-extensions.github.io/maps/v1.0.0/schema.json"
"https://stac-extensions.github.io/maps/v1.0.0/schema.json",
"https://stac-extensions.github.io/web-map-links/v1.3.0/schema.json"
],
"type": "Collection",
"id": "collection",
"title": "A title",
"description": "A description",
"license": "Apache-2.0",
"title": "Yearly mosaics",
"description": "Cloud-free yearly mosaics",
"license": "CC-BY-4.0",
"extent": {
"spatial": {
"bbox": [
[
172.9,
1.3,
173,
1.4
9,
47.7,
10.5,
48.7
]
]
},
"temporal": {
"interval": [
[
"2015-06-23T00:00:00Z",
"2015-01-01T00:00:00Z",
null
]
]
}
},
"maps": {
"mosaic": {
"title": "Latest mosaic over a basemap",
"roles": [
"default"
],
"proj:code": "EPSG:3857",
"dimensions": {
"time": "2025"
},
"layers": [
{
"link": {
"rel": "xyz",
"href": "https://basemap.example.com/{z}/{x}/{y}.png",
"type": "image/png",
"title": "Basemap"
}
},
{
"link": "mosaic-wmts",
"opacity": 0.9
}
]
}
},
"links": [
{
"href": "https://example.com/examples/collection.json",
Expand All @@ -36,6 +63,14 @@
{
"href": "https://example.com/examples/item.json",
"rel": "item"
},
{
"id": "mosaic-wmts",
"rel": "wmts",
"href": "https://maps.example.com/wmts",
"type": "image/png",
"title": "Yearly mosaic",
"wmts:layer": "mosaic"
}
]
}
}
Loading
Loading