add terrain preview and elevation link

This commit is contained in:
Miko 2024-10-13 21:27:40 +02:00
parent 760653901e
commit f60de38304
5 changed files with 132 additions and 56 deletions

View file

@ -114,7 +114,7 @@ section {
} }
.details h3 { .details h3 {
font-size: 18px; font-size: 18px;
margin-top: 25px; margin-top: 5px;
} }
.details p { .details p {
padding: 0; padding: 0;

View file

@ -4,20 +4,25 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{name}} - TileServer GL</title> <title>{{name}} - TileServer GL</title>
{{#is_vector}} {{#use_maplibre}}
<link rel="stylesheet" type="text/css" href="{{public_url}}maplibre-gl.css{{&key_query}}" /> <link rel="stylesheet" type="text/css" href="{{public_url}}maplibre-gl.css{{&key_query}}" />
<link rel="stylesheet" type="text/css" href="{{public_url}}maplibre-gl-inspect.css{{&key_query}}" /> <link rel="stylesheet" type="text/css" href="{{public_url}}maplibre-gl-inspect.css{{&key_query}}" />
<script src="{{public_url}}maplibre-gl.js{{&key_query}}"></script> <script src="{{public_url}}maplibre-gl.js{{&key_query}}"></script>
<script src="{{public_url}}maplibre-gl-inspect.js{{&key_query}}"></script> <script src="{{public_url}}maplibre-gl-inspect.js{{&key_query}}"></script>
<style> <style>
body {background:#fff;color:#333;font-family:Arial, sans-serif;} body {background:#fff;color:#333;font-family:Arial, sans-serif;}
{{^is_terrain}}
#map {position:absolute;top:0;left:0;right:250px;bottom:0;} #map {position:absolute;top:0;left:0;right:250px;bottom:0;}
{{/is_terrain}}
{{#is_terrain}}
#map { position:absolute; top:0; bottom:0; width:100%; }
{{/is_terrain}}
h1 {position:absolute;top:5px;right:0;width:240px;margin:0;line-height:20px;font-size:20px;} h1 {position:absolute;top:5px;right:0;width:240px;margin:0;line-height:20px;font-size:20px;}
#layerList {position:absolute;top:35px;right:0;bottom:0;width:240px;overflow:auto;} #layerList {position:absolute;top:35px;right:0;bottom:0;width:240px;overflow:auto;}
#layerList div div {width:15px;height:15px;display:inline-block;} #layerList div div {width:15px;height:15px;display:inline-block;}
</style> </style>
{{/is_vector}} {{/use_maplibre}}
{{^is_vector}} {{^use_maplibre}}
<link rel="stylesheet" type="text/css" href="{{public_url}}leaflet.css{{&key_query}}" /> <link rel="stylesheet" type="text/css" href="{{public_url}}leaflet.css{{&key_query}}" />
<script src="{{public_url}}leaflet.js{{&key_query}}"></script> <script src="{{public_url}}leaflet.js{{&key_query}}"></script>
<script src="{{public_url}}leaflet-hash.js{{&key_query}}"></script> <script src="{{public_url}}leaflet-hash.js{{&key_query}}"></script>
@ -37,23 +42,22 @@
background-image: url({{public_url}}images/marker-icon.png{{&key_query}}); background-image: url({{public_url}}images/marker-icon.png{{&key_query}});
} }
</style> </style>
{{/is_vector}} {{/use_maplibre}}
</head> </head>
<body> <body>
{{#is_vector}} {{#use_maplibre}}
<h1>{{name}}</h1> <h1>{{name}}</h1>
<div id="map"></div> <div id="map"></div>
{{^is_terrain}}
<div id="layerList"></div> <div id="layerList"></div>
<pre id="propertyList"></pre> <pre id="propertyList"></pre>
{{/is_terrain}}
<script> <script>
var keyMatch = location.search.match(/[\?\&]key=([^&]+)/i); var keyMatch = location.search.match(/[\?\&]key=([^&]+)/i);
var keyParam = keyMatch ? '?key=' + keyMatch[1] : ''; var keyParam = keyMatch ? '?key=' + keyMatch[1] : '';
var map = new maplibregl.Map({ {{^is_terrain}}
container: 'map', var style = {
hash: true,
maxPitch: 85,
style: {
version: 8, version: 8,
sources: { sources: {
'vector_layer_': { 'vector_layer_': {
@ -62,37 +66,88 @@
} }
}, },
layers: [] layers: []
} };
}); {{/is_terrain}}
map.addControl(new maplibregl.NavigationControl()); {{#is_terrain}}
var inspect = new MaplibreInspect({ var style = {
showInspectMap: true, version: 8,
showInspectButton: false sources: {
}); "terrain": {
map.addControl(inspect); "type": "raster-dem",
map.on('styledata', function() { "url": "{{public_url}}data/{{id}}.json",
var layerList = document.getElementById('layerList'); "encoding": "{{terrain_encoding}}"
layerList.innerHTML = ''; },
Object.keys(inspect.sources).forEach(function(sourceId) { "hillshade": {
var layerIds = inspect.sources[sourceId]; "type": "raster-dem",
layerIds.forEach(function(layerId) { "url": "{{public_url}}data/{{id}}.json",
var item = document.createElement('div'); "encoding": "{{terrain_encoding}}"
item.innerHTML = '<div style="' + }
'background:' + inspect.assignLayerColor(layerId) + ';' + },
'"></div> ' + layerId; "terrain": {
layerList.appendChild(item); "source": "terrain"
}); },
}) layers: [
}); {
"id": "background",
"paint": {
{{^if is_terrainrgb}}
"background-color": "hsl(190, 99%, 63%)"
{{else}}
"background-color": "hsl(0, 100%, 25%)"
{{/if}}
},
"type": "background"
},
{
"id": "hillshade",
"source": "hillshade",
"type": "hillshade",
"paint": {
"hillshade-shadow-color": "hsl(39, 21%, 33%)",
"hillshade-illumination-direction": 315,
"hillshade-exaggeration": 0.8
}
}
]
};
{{/is_terrain}}
var map = new maplibregl.Map({
container: 'map',
hash: true,
maxPitch: 85,
style: style
});
map.addControl(new maplibregl.NavigationControl());
{{^is_terrain}}
var inspect = new MaplibreInspect({
showInspectMap: true,
showInspectButton: false
});
map.addControl(inspect);
map.on('styledata', function() {
var layerList = document.getElementById('layerList');
layerList.innerHTML = '';
Object.keys(inspect.sources).forEach(function(sourceId) {
var layerIds = inspect.sources[sourceId];
layerIds.forEach(function(layerId) {
var item = document.createElement('div');
item.innerHTML = '<div style="' +
'background:' + inspect.assignLayerColor(layerId) + ';' +
'"></div> ' + layerId;
layerList.appendChild(item);
});
})
});
{{/is_terrain}}
</script> </script>
{{/is_vector}} {{/use_maplibre}}
{{^is_vector}} {{^use_maplibre}}
<h1 style="display:none;">{{name}}</h1> <h1 style="display:none;">{{name}}</h1>
<div id='map'></div> <div id='map'></div>
<script> <script>
var keyMatch = location.search.match(/[\?\&]key=([^&]+)/i); var keyMatch = location.search.match(/[\?\&]key=([^&]+)/i);
var keyParam = keyMatch ? '?key=' + keyMatch[1] : ''; var keyParam = keyMatch ? '?key=' + keyMatch[1] : '';
var map = L.map('map', { zoomControl: false }); var map = L.map('map', { zoomControl: false });
new L.Control.Zoom({ position: 'topright' }).addTo(map); new L.Control.Zoom({ position: 'topright' }).addTo(map);
@ -129,7 +184,7 @@
attribution: tile_attribution attribution: tile_attribution
}).addTo(map); }).addTo(map);
} }
map.eachLayer(function(layer) { map.eachLayer(function(layer) {
// do not add scale prefix even if retina display is detected // do not add scale prefix even if retina display is detected
layer.scalePrefix = '.'; layer.scalePrefix = '.';
@ -141,6 +196,6 @@
new L.Hash(map); new L.Hash(map);
}, 0); }, 0);
</script> </script>
{{/is_vector}} {{/use_maplibre}}
</body> </body>
</html> </html>

View file

@ -6,10 +6,15 @@
<title>TileServer GL - Server for vector and raster maps with GL styles</title> <title>TileServer GL - Server for vector and raster maps with GL styles</title>
<link rel="stylesheet" type="text/css" href="{{public_url}}index.css{{&key_query}}" /> <link rel="stylesheet" type="text/css" href="{{public_url}}index.css{{&key_query}}" />
<script> <script>
function toggle_xyz(id) { function toggle_link(id, link) {
var el = document.getElementById(id); var el = document.getElementById(id);
var s = el.style; var s = el.style;
s.display = s.display == 'none' ? 'inline-block' : 'none'; if (s.display == 'none') {
s.display = 'inline-block';
} else if (el.value == link) {
s.display = 'none';
}
el.value = link;
el.setSelectionRange(0, el.value.length); el.setSelectionRange(0, el.value.length);
return false; return false;
} }
@ -37,7 +42,7 @@
<div class="filter-details"> <div class="filter-details">
<h3>Filter styles and data by name or identifier</h3> <h3>Filter styles and data by name or identifier</h3>
<!-- filter input , needs to call filter() when content changes...--> <!-- filter input , needs to call filter() when content changes...-->
<input id="filter" type="text" oninput="filter()" placeholder="Start typing name or identifier" /> <input id="filter" type="text" oninput="filter()" placeholder="Start typing name or identifier" autofocus />
</div> </div>
</div> </div>
</div> </div>
@ -66,8 +71,8 @@
| <a href="{{public_url}}styles/{{@key}}/wmts.xml{{&../key_query}}">WMTS</a> | <a href="{{public_url}}styles/{{@key}}/wmts.xml{{&../key_query}}">WMTS</a>
{{/if}} {{/if}}
{{#if xyz_link}} {{#if xyz_link}}
| <a href="#" onclick="return toggle_xyz('xyz_style_{{@key}}');">XYZ</a> | <a href="#" onclick="return toggle_link('xyz_style_{{@key}}', '{{&xyz_link}}');">XYZ</a>
<input id="xyz_style_{{@key}}" type="text" value="{{&xyz_link}}" style="display:none;" /> <input id="xyz_style_{{@key}}" type="text" value="" style="display:none;" />
{{/if}} {{/if}}
</p> </p>
</div> </div>
@ -105,9 +110,12 @@
<p class="services"> <p class="services">
services: <a href="{{public_url}}data/{{@key}}.json{{&../key_query}}">TileJSON</a> services: <a href="{{public_url}}data/{{@key}}.json{{&../key_query}}">TileJSON</a>
{{#if xyz_link}} {{#if xyz_link}}
| <a href="#" onclick="return toggle_xyz('xyz_data_{{@key}}');">XYZ</a> | <a href="#" onclick="return toggle_link('link_data_{{@key}}', '{{&xyz_link}}');">XYZ</a>
<input id="xyz_data_{{@key}}" type="text" value="{{&xyz_link}}" style="display:none;" />
{{/if}} {{/if}}
{{#if elevation_link}}
| <a href="#" onclick="return toggle_link('link_data_{{@key}}', '{{&elevation_link}}');">Elevation</a>
{{/if}}
<input id="link_data_{{@key}}" type="text" value="" style="display:none;" />
</p> </p>
</div> </div>
<div class="viewers"> <div class="viewers">
@ -116,6 +124,9 @@
{{/is_vector}} {{/is_vector}}
{{^is_vector}} {{^is_vector}}
<a class="btn" href="{{public_url}}data/{{@key}}/{{&../key_query}}{{viewer_hash}}">View</a> <a class="btn" href="{{public_url}}data/{{@key}}/{{&../key_query}}{{viewer_hash}}">View</a>
{{#elevation_link}}
<a class="btn" href="{{public_url}}data/preview/{{@key}}/{{&../key_query}}{{viewer_hash}}">Preview</a>
{{/elevation_link}}
{{/is_vector}} {{/is_vector}}
</div> </div>
</div> </div>

View file

@ -595,18 +595,22 @@ function start(opts) {
}; };
}); });
serveTemplate('/data/:id/$', 'data', (req) => { serveTemplate('/data/(:preview(preview)/)?:id/', 'data', (req) => {
const { id } = req.params; const id = req.params.id;
const preview = req.params.preview || undefined;
const data = serving.data[id]; const data = serving.data[id];
if (!data) { if (!data) {
return null; return null;
} }
const is_terrain = ((data.tileJSON.encoding === 'terrarium' || data.tileJSON.encoding === 'mapbox') && (preview === "preview"));
return { return {
...data, ...data,
id, id,
is_vector: data.tileJSON.format === 'pbf', use_maplibre: (data.tileJSON.format === 'pbf' || is_terrain),
is_terrain: is_terrain,
is_terrainrgb: (data.tileJSON.encoding === "mapbox"),
terrain_encoding: data.tileJSON.encoding,
}; };
}); });

View file

@ -119,16 +119,22 @@ export const getTileUrls = (
tileParams = `${tileSize}/{z}/{x}/{y}`; tileParams = `${tileSize}/{z}/{x}/{y}`;
} }
if (format && format != "") {
format = `.${format}`;
} else {
format = "";
}
const uris = []; const uris = [];
if (!publicUrl) { if (!publicUrl) {
let xForwardedPath = `${req.get('X-Forwarded-Path') ? '/' + req.get('X-Forwarded-Path') : ''}`; let xForwardedPath = `${req.get('X-Forwarded-Path') ? '/' + req.get('X-Forwarded-Path') : ''}`;
for (const domain of domains) { for (const domain of domains) {
uris.push( uris.push(
`${req.protocol}://${domain}${xForwardedPath}/${path}/${tileParams}.${format}${query}`, `${req.protocol}://${domain}${xForwardedPath}/${path}/${tileParams}${format}${query}`,
); );
} }
} else { } else {
uris.push(`${publicUrl}${path}/${tileParams}.${format}${query}`); uris.push(`${publicUrl}${path}/${tileParams}${format}${query}`);
} }
return uris; return uris;