Skip to content

Commit

Permalink
try proj4leaflet to support projection in /map viewer (#560)
Browse files Browse the repository at this point in the history
* try proj4leaflet to support projection in viewew

* add markers

* update template

* remove points

* update changelog
  • Loading branch information
vincentsarago authored Dec 14, 2022
1 parent 650f6e4 commit 5588da0
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 116 deletions.
4 changes: 4 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Release Notes

## 0.10.1 (2022-12-15)

* update `/map` endpoint and template to support multiple TMS (https://github.com/developmentseed/titiler/pull/560)

## 0.10.0 (2022-12-09)

**breaking change**
Expand Down
2 changes: 1 addition & 1 deletion docs/src/endpoints/cog.md
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ Example:
`:endpoint:/cog[/{TileMatrixSetId}]/map` Simple viewer

- PathParams:
- **TileMatrixSetId**: TileMatrixSet name (only `WebMercatorQuad` is supported). **Optional**
- **TileMatrixSetId**: TileMatrixSet name, default is `WebMercatorQuad`. **Optional**

- QueryParams:
- **url** (str): Cloud Optimized GeoTIFF URL. **Required**
Expand Down
2 changes: 1 addition & 1 deletion docs/src/endpoints/stac.md
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ Example:
`:endpoint:/stac[/{TileMatrixSetId}]/map` Simple viewer

- PathParams:
- **TileMatrixSetId**: TileMatrixSet name (only `WebMercatorQuad` is supported). **Optional**
- **TileMatrixSetId**: TileMatrixSet name, default is `WebMercatorQuad`. **Optional**

- QueryParams:
- **url** (str): STAC Item URL. **Required**
Expand Down
13 changes: 9 additions & 4 deletions src/titiler/core/titiler/core/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -633,9 +633,9 @@ def map_viewer(self): # noqa: C901
def map_viewer(
request: Request,
src_path=Depends(self.path_dependency),
TileMatrixSetId: Literal["WebMercatorQuad"] = Query(
"WebMercatorQuad",
description="TileMatrixSet Name (default: 'WebMercatorQuad')",
TileMatrixSetId: Literal[tuple(self.supported_tms.list())] = Query(
self.default_tms,
description=f"TileMatrixSet Name (default: '{self.default_tms}')",
), # noqa
tile_format: Optional[ImageType] = Query(
None, description="Output image type. Default is auto."
Expand Down Expand Up @@ -672,15 +672,20 @@ def map_viewer(
env=Depends(self.environment_dependency), # noqa
):
"""Return TileJSON document for a dataset."""
tilejson_url = self.url_for(request, "tilejson")
tilejson_url = self.url_for(
request, "tilejson", TileMatrixSetId=TileMatrixSetId
)
if request.query_params._list:
tilejson_url += f"?{urlencode(request.query_params._list)}"

tms = self.supported_tms.get(TileMatrixSetId)
return templates.TemplateResponse(
name="index.html",
context={
"request": request,
"tilejson_endpoint": tilejson_url,
"tms": tms,
"resolutions": [tms._resolution(matrix) for matrix in tms],
},
media_type="text/html",
)
Expand Down
163 changes: 59 additions & 104 deletions src/titiler/core/titiler/core/templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,53 +4,20 @@
<meta charset='utf-8' />
<title>TiTiler Map Viewer</title>
<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
<script src='https://unpkg.com/[email protected]/dist/maplibre-gl.js'></script>
<link href='https://unpkg.com/[email protected]/dist/maplibre-gl.css' rel='stylesheet' />

<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css"/>
<script src="https://unpkg.com/[email protected]/dist/leaflet.js"></script>
<script src="https://unpkg.com/[email protected]/dist/proj4.js"></script>
<script src="https://unpkg.com/[email protected]/src/proj4leaflet.js"></script>
<style>
body { margin:0; padding:0; width:100%; height:100%; background-color: #e5e5e5;}
#map { position:absolute; top:0; bottom:0; width:100%; }
.zoom-info {
z-index: 10;
position: absolute;
bottom: 0;
right: 0;
padding: 5px;
width: auto;
height: auto;
font-size: 12px;
color: #000;
}
@media(max-width: 767px) {
.maplibrectrl-attrib {
font-size: 10px;
}
}
</style>
</head>
<body>

<div id='map'>
<div class="zoom-info">Zoom: <span id="zoom"></span></div>
</div>

<script>
<div id='map'></div>

var map = new maplibregl.Map({
container: 'map',
style: {
version: 8,
sources: {},
layers: []
},
center: [0, 0],
zoom: 1
})

map.on('zoom', function (e) {
const z = (map.getZoom()).toString().slice(0, 4)
document.getElementById('zoom').textContent = z
})
<script type="text/javascript">

const bboxPolygon = (bounds) => {
return {
Expand All @@ -69,79 +36,67 @@
}
}

const addAOI = (bounds) => {
if (map.getLayer('aoi-polygon')) map.removeLayer('aoi-polygon')
if (map.getSource('aoi')) map.removeSource('aoi')
const geojson = {
"type": "FeatureCollection",
"features": [bboxPolygon(bounds)]
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 }},
}
);

map.addSource('aoi', {
'type': 'geojson',
'data': geojson
})

map.addLayer({
id: 'aoi-polygon',
type: 'line',
source: 'aoi',
layout: {
'line-cap': 'round',
'line-join': 'round'
},
paint: {
'line-color': '#3bb2d0',
'line-width': 1
}
})
return
}

map.on('load', () => {
var map = L.map('map', {
crs: crs,
minZoom: {{ tms.minzoom }},
maxZoom: {{ tms.maxzoom }}
});

fetch('{{ tilejson_endpoint|safe }}')
.then(res => {
if (res.ok) return res.json()
throw new Error('Network response was not ok.')
})
.then(data => {
console.log(data)
// const nullIsland = L.marker([0, 0]).addTo(map);
// const madrid = L.marker([40, -3]).addTo(map);
// const london = L.marker([51.50722, -0.1275]).addTo(map)
// const auckland = L.marker([-36.864664, 174.792059]).addTo(map);
// const seattle = L.marker([47.596842, -122.333087]).addTo(map);

let bounds = [...data.bounds]
// Bounds crossing dateline
if (bounds[0] > bounds[2]) {
bounds[0] = bounds[0] - 360
}
map.fitBounds(
[[bounds[0], bounds[1]], [bounds[2], bounds[3]]]
)
addAOI(bounds)
fetch('{{ tilejson_endpoint|safe }}')
.then(res => {
if (res.ok) return res.json()
throw new Error('Network response was not ok.')
})
.then(data => {
console.log(data)

map.addSource(
'raster',
{
type: 'raster',
bounds: data.bounds,
minzoom: data.minzoom,
maxzoom: data.maxzoom,
tiles: data.tiles,
}
)
let bounds = [...data.bounds]
// Bounds crossing dateline
if (bounds[0] > bounds[2]) {
bounds[0] = bounds[0] - 360
}
var left = bounds[0],
bottom = bounds[1],
right = bounds[2],
top = bounds[3];

map.addLayer(
{
id: 'raster',
type: 'raster',
source: 'raster',
}
)
var aoi = L.geoJSON(
bboxPolygon(bounds), {
color: '#3bb2d0', fill: false
}
).addTo(map);
map.fitBounds(aoi.getBounds());

})
.catch(err => {
console.warn(err)
})
})
L.tileLayer(
data.tiles[0], {
minZoom: data.minzoom,
maxNativeZoom: data.maxzoom,
bounds: L.latLngBounds([bottom, left], [top, right]),
}
).addTo(map);
})
.catch(err => {
console.warn(err)
})
</script>
</body>
</html>
17 changes: 11 additions & 6 deletions src/titiler/mosaic/titiler/mosaic/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -428,15 +428,15 @@ def tilejson(
def map_viewer(self): # noqa: C901
"""Register /map endpoint."""

@self.router.get("/{TileMatrixSetId}/map", response_class=HTMLResponse)
@self.router.get("/map", response_class=HTMLResponse)
@self.router.get("/{TileMatrixSetId}/map", response_class=HTMLResponse)
def map_viewer(
request: Request,
src_path=Depends(self.path_dependency),
TileMatrixSetId: Literal["WebMercatorQuad"] = Query(
"WebMercatorQuad",
description="TileMatrixSet Name (default: 'WebMercatorQuad')",
), # noqa
TileMatrixSetId: Literal[tuple(self.supported_tms.list())] = Query(
self.default_tms,
description=f"TileMatrixSet Name (default: '{self.default_tms}')",
),
tile_format: Optional[ImageType] = Query(
None, description="Output image type. Default is auto."
),
Expand Down Expand Up @@ -473,15 +473,20 @@ def map_viewer(
env=Depends(self.environment_dependency), # noqa
):
"""Return TileJSON document for a dataset."""
tilejson_url = self.url_for(request, "tilejson")
tilejson_url = self.url_for(
request, "tilejson", TileMatrixSetId=TileMatrixSetId
)
if request.query_params._list:
tilejson_url += f"?{urlencode(request.query_params._list)}"

tms = self.supported_tms.get(TileMatrixSetId)
return templates.TemplateResponse(
name="index.html",
context={
"request": request,
"tilejson_endpoint": tilejson_url,
"tms": tms,
"resolutions": [tms._resolution(matrix) for matrix in tms],
},
media_type="text/html",
)
Expand Down

0 comments on commit 5588da0

Please sign in to comment.