From 5e4f72c6b0a4ec651d03c4db526929fce898987a Mon Sep 17 00:00:00 2001 From: vincentsarago Date: Thu, 8 Feb 2024 14:12:16 +0100 Subject: [PATCH] add map endpoint --- titiler/cmr/backend.py | 13 +- titiler/cmr/factory.py | 82 ++++++++-- titiler/cmr/templates/header.html | 1 - titiler/cmr/templates/map.html | 250 +++++++++++++++--------------- 4 files changed, 199 insertions(+), 147 deletions(-) diff --git a/titiler/cmr/backend.py b/titiler/cmr/backend.py index 00d237f..5098940 100644 --- a/titiler/cmr/backend.py +++ b/titiler/cmr/backend.py @@ -163,11 +163,14 @@ def get_assets( **kwargs: Any, ) -> List[Asset]: """Find assets.""" - results = earthaccess.search_data( - bounding_box=(xmin, ymin, xmax, ymax), - count=limit, - **kwargs, - ) + try: + results = earthaccess.search_data( + bounding_box=(xmin, ymin, xmax, ymax), + count=limit, + **kwargs, + ) + except RuntimeError: + return [] assets: List[Asset] = [] for r in results: diff --git a/titiler/cmr/factory.py b/titiler/cmr/factory.py index 341db62..392b856 100644 --- a/titiler/cmr/factory.py +++ b/titiler/cmr/factory.py @@ -17,7 +17,7 @@ from rio_tiler.io import Reader from rio_tiler.types import RIOResampling, WarpResampling from starlette.requests import Request -from starlette.responses import Response +from starlette.responses import HTMLResponse, Response from starlette.routing import compile_path, replace_params from starlette.templating import Jinja2Templates, _TemplateResponse from typing_extensions import Annotated @@ -142,6 +142,7 @@ def __post_init__(self): self.register_conformance() self.register_tilematrixsets() self.register_tiles() + self.register_map() def register_landing(self) -> None: """register landing page endpoint.""" @@ -577,7 +578,7 @@ def tiles_endpoint( return Response(content, media_type=media_type) @self.router.get( - "/collections/{collectionId}/{tileMatrixSetId}/tilejson.json", + "/{tileMatrixSetId}/tilejson.json", response_model=TileJSON, responses={200: {"description": "Return a tilejson"}}, response_model_exclude_none=True, @@ -585,12 +586,6 @@ def tiles_endpoint( ) def tilejson_endpoint( # type: ignore request: Request, - collectionId: Annotated[ - str, - Path( - description="A CMR concept id, in the format '-' " - ), - ], tileMatrixSetId: Annotated[ Literal[tuple(self.supported_tms.list())], Path(description="Identifier for a supported TileMatrixSet"), @@ -620,9 +615,9 @@ def tilejson_endpoint( # type: ignore query=Depends(cmr_query), ################################################################### backend: Annotated[ - Literal["cog", "xarray"], + Literal["rasterio", "xarray"], Query(description="Backend to read the CMR dataset"), - ] = "cog", + ] = "rasterio", ################################################################### # ZarrReader Options ################################################################### @@ -732,10 +727,10 @@ def tilejson_endpoint( # type: ignore tms = self.supported_tms.get(tileMatrixSetId) - # TODO: can we get metadata from the collection? + # TODO: can we get metadata from the CMR dataset? with CMRBackend( - auth=request.app.state.cmr_auth, tms=tms, + auth=request.app.state.cmr_auth, ) as src_dst: minx, miny, maxx, maxy = zip( [-180, -90, 180, 90], list(src_dst.geographic_bounds) @@ -748,3 +743,66 @@ def tilejson_endpoint( # type: ignore "maxzoom": maxzoom if maxzoom is not None else src_dst.maxzoom, "tiles": [tiles_url], } + + def register_map(self): # noqa: C901 + """Register map endpoints.""" + + @self.router.get( + "/{tileMatrixSetId}/map", + response_class=HTMLResponse, + responses={200: {"description": "Return a Map document"}}, + tags=["Map"], + ) + def map_endpoint( # type: ignore + request: Request, + tileMatrixSetId: Annotated[ + Literal[tuple(self.supported_tms.list())], + Path(description="Identifier for a supported TileMatrixSet"), + ], + minzoom: Annotated[ + Optional[int], + Query(description="Overwrite default minzoom."), + ] = None, + maxzoom: Annotated[ + Optional[int], + Query(description="Overwrite default maxzoom."), + ] = None, + ) -> Dict: + """Return Map document.""" + tilejson_url = self.url_for( + request, + "tilejson_endpoint", + tileMatrixSetId=tileMatrixSetId, + ) + if request.query_params._list: + tilejson_url += f"?{urlencode(request.query_params._list)}" + + tms = self.supported_tms.get(tileMatrixSetId) + + base_url = str(request.base_url).rstrip("/") + if self.router_prefix: + prefix = self.router_prefix.lstrip("/") + # If we have prefix with custom path param we check and replace them with + # the path params provided + if "{" in prefix: + _, path_format, param_convertors = compile_path(prefix) + prefix, _ = replace_params( + path_format, param_convertors, request.path_params.copy() + ) + base_url += prefix + + return self.templates.TemplateResponse( + name="map.html", + context={ + "request": request, + "tilejson_endpoint": tilejson_url, + "tms": tms, + "resolutions": [matrix.cellSize for matrix in tms], + "template": { + "api_root": base_url, + "params": request.query_params, + "title": "Map", + }, + }, + media_type="text/html", + ) diff --git a/titiler/cmr/templates/header.html b/titiler/cmr/templates/header.html index 261bee5..05d1ac4 100644 --- a/titiler/cmr/templates/header.html +++ b/titiler/cmr/templates/header.html @@ -33,7 +33,6 @@ diff --git a/titiler/cmr/templates/map.html b/titiler/cmr/templates/map.html index 511d3fc..e67283a 100644 --- a/titiler/cmr/templates/map.html +++ b/titiler/cmr/templates/map.html @@ -1,63 +1,90 @@ - + + + {{ template.title }} + + + + + + + + + + + + + - - - TiPG Map Viewer - +
+
+
- - - - - + var crs = new L.Proj.CRS( + '{{ tms.crs.srs }}', + '{{ tms.crs.to_proj4() }}', { + origin: [{{ tms.xy_bbox.left }}, {{ tms.xy_bbox.top }}], + bounds: L.bounds( + L.Point({{ tms.xy_bbox.left}}, {{ tms.xy_bbox.bottom }}), + L.Point({{ tms.xy_bbox.right}}, {{ tms.xy_bbox.top }}) + ), + resolutions: {{ resolutions|safe }}, + } + ); - -
- - + + +