This commit is contained in:
Michael Straßburger 2016-12-06 03:10:55 +00:00 committed by GitHub
commit 19cb2f6b8d
10 changed files with 76 additions and 48 deletions

View file

@ -66,6 +66,16 @@ The value of ``root`` is used as prefix for all data types.
You can use this to optionally specify on what domains the rendered tiles are accessible. This can be used for basic load-balancing or to bypass browser's limit for the number of connections per domain. You can use this to optionally specify on what domains the rendered tiles are accessible. This can be used for basic load-balancing or to bypass browser's limit for the number of connections per domain.
``baseURL``
-----------
When you run the tile server server behind a load-balancer, the automatic URL generators wont't have the required information to build URLs which point to the correct LB endpoint.
Also, if your load balancer is forwarding a HTTPS connection to the non-HTTPS ``tileserver-gl``, setting the ``baseURL`` is indispensable.
Not compatible with the ``domains`` option.
``formatQuality`` ``formatQuality``
----------------- -----------------

View file

@ -1,18 +1,18 @@
@font-face { @font-face {
font-family: 'OpenSans'; font-family: 'OpenSans';
src: url('/fonts/OpenSans-Regular.ttf'); src: url('fonts/OpenSans-Regular.ttf');
font-weight: normal; font-weight: normal;
font-style: normal; font-style: normal;
} }
@font-face { @font-face {
font-family: 'OpenSans'; font-family: 'OpenSans';
src: url('/fonts/OpenSans-Italic.ttf'); src: url('fonts/OpenSans-Italic.ttf');
font-weight: normal; font-weight: normal;
font-style: italic; font-style: italic;
} }
@font-face { @font-face {
font-family: 'OpenSans'; font-family: 'OpenSans';
src: url('/fonts/OpenSans-Bold.ttf'); src: url('fonts/OpenSans-Bold.ttf');
font-weight: bold; font-weight: bold;
font-style: normal; font-style: normal;
} }
@ -149,21 +149,21 @@ footer a {
body { body {
background-repeat:no-repeat !important; background-repeat:no-repeat !important;
background-size: contain !important; background-size: contain !important;
background-image: url(/images/header-map-640px.png); background-image: url(images/header-map-640px.png);
} }
@media only screen and (min-width: 641px) { @media only screen and (min-width: 641px) {
body { body {
background-image: url(/images/header-map-1280px.png); background-image: url(images/header-map-1280px.png);
} }
} }
@media only screen and (min-width: 1281px) { @media only screen and (min-width: 1281px) {
body { body {
background-image: url(/images/header-map-1600px.png); background-image: url(images/header-map-1600px.png);
} }
} }
@media only screen and (min-width: 1601px) { @media only screen and (min-width: 1601px) {
body { body {
background-image: url(/images/header-map-2560px.png); background-image: url(images/header-map-2560px.png);
} }
} }
@ -209,4 +209,4 @@ body {
.btn:first-child{ .btn:first-child{
padding: 0 20px; padding: 0 20px;
} }
} }

View file

@ -5,8 +5,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}} {{#is_vector}}
<link rel="stylesheet" type="text/css" href="/mapbox-gl.css{{&key_query}}" /> <link rel="stylesheet" type="text/css" href="{{baseURL}}/mapbox-gl.css{{&key_query}}" />
<script src="/mapbox-gl.js{{&key_query}}"></script> <script src="{{baseURL}}/mapbox-gl.js{{&key_query}}"></script>
<style> <style>
body {background:#000;color:#ccc;} body {background:#000;color:#ccc;}
#map {position:absolute;top:0;left:0;right:250px;bottom:0;} #map {position:absolute;top:0;left:0;right:250px;bottom:0;}
@ -17,9 +17,9 @@
</style> </style>
{{/is_vector}} {{/is_vector}}
{{^is_vector}} {{^is_vector}}
<link rel="stylesheet" type="text/css" href="/mapbox.css{{&key_query}}" /> <link rel="stylesheet" type="text/css" href="{{baseURL}}/mapbox.css{{&key_query}}" />
<script src="/mapbox.js{{&key_query}}"></script> <script src="{{baseURL}}/mapbox.js{{&key_query}}"></script>
<script src="/leaflet-hash.js{{&key_query}}"></script> <script src="{{baseURL}}/leaflet-hash.js{{&key_query}}"></script>
<style> <style>
body { margin:0; padding:0; } body { margin:0; padding:0; }
#map { position:absolute; top:0; bottom:0; width:100%; } #map { position:absolute; top:0; bottom:0; width:100%; }
@ -108,7 +108,7 @@
} }
}; };
xhttp.responseType = 'json'; xhttp.responseType = 'json';
xhttp.open('GET', '/data/{{id}}.json{{&key_query}}', true); xhttp.open('GET', '{{baseURL}}/data/{{id}}.json{{&key_query}}', true);
xhttp.send(); xhttp.send();
var propertyList = document.getElementById('propertyList'); var propertyList = document.getElementById('propertyList');
@ -133,7 +133,7 @@
<h1 style="display:none;">{{name}}</h1> <h1 style="display:none;">{{name}}</h1>
<div id='map'></div> <div id='map'></div>
<script> <script>
var map = L.mapbox.map('map', '/data/{{id}}.json{{&key_query}}', { zoomControl: false }); var map = L.mapbox.map('map', '{{baseURL}}/data/{{id}}.json{{&key_query}}', { zoomControl: false });
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 = '.';

View file

@ -4,7 +4,7 @@
<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>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="/index.css{{&key_query}}" /> <link rel="stylesheet" type="text/css" href="{{baseURL}}/index.css{{&key_query}}" />
<script> <script>
function toggle_xyz(id) { function toggle_xyz(id) {
var el = document.getElementById(id); var el = document.getElementById(id);
@ -17,23 +17,23 @@
</head> </head>
<body> <body>
<section> <section>
<h1 class="title {{#if is_light}}light{{/if}}"><img src="/images/logo.png" alt="TileServer GL" /></h1> <h1 class="title {{#if is_light}}light{{/if}}"><img src="{{baseURL}}/images/logo.png" alt="TileServer GL" /></h1>
<h2 class="subtitle">Vector {{#if is_light}}<s>and raster</s>{{else}}and raster{{/if}} maps with GL styles</h2> <h2 class="subtitle">Vector {{#if is_light}}<s>and raster</s>{{else}}and raster{{/if}} maps with GL styles</h2>
<h2 class="box-header">Styles</h2> <h2 class="box-header">Styles</h2>
<div class="box"> <div class="box">
{{#each styles}} {{#each styles}}
<div class="item"> <div class="item">
{{#if thumbnail}} {{#if thumbnail}}
<img src="/styles/{{@key}}/rendered/{{thumbnail}}{{&../key_query}}" alt="{{name}} preview" /> <img src="{{baseURL}}/styles/{{@key}}/rendered/{{thumbnail}}{{&../key_query}}" alt="{{name}} preview" />
{{else}} {{else}}
<img src="/images/placeholder.png" alt="{{name}} preview" /> <img src="{{baseURL}}/images/placeholder.png" alt="{{name}} preview" />
{{/if}} {{/if}}
<div class="details"> <div class="details">
<h3>{{name}}</h3> <h3>{{name}}</h3>
<p class="identifier">identifier: {{@key}}</p> <p class="identifier">identifier: {{@key}}</p>
<p class="services"> <p class="services">
{{#if serving_rendered}} {{#if serving_rendered}}
services: <a href="/styles/{{@key}}/rendered.json{{&../key_query}}">TileJSON</a> services: <a href="{{baseURL}}/styles/{{@key}}/rendered.json{{&../key_query}}">TileJSON</a>
{{/if}} {{/if}}
{{#if wmts_link}} {{#if wmts_link}}
| <a href="{{&wmts_link}}">WMTS</a> | <a href="{{&wmts_link}}">WMTS</a>
@ -47,14 +47,14 @@
<div class="viewers"> <div class="viewers">
{{#if serving_data}} {{#if serving_data}}
{{#if serving_rendered}} {{#if serving_rendered}}
<a class="btn" href="/styles/{{@key}}/{{&../key_query}}{{viewer_hash}}">Viewer</a> <a class="btn" href="{{baseURL}}/styles/{{@key}}/{{&../key_query}}{{viewer_hash}}">Viewer</a>
{{/if}} {{/if}}
{{/if}} {{/if}}
{{#if serving_rendered}} {{#if serving_rendered}}
<a class="btn" href="/styles/{{@key}}/?{{&../key_query_part}}raster{{viewer_hash}}">Raster</a> <a class="btn" href="{{baseURL}}/styles/{{@key}}/?{{&../key_query_part}}raster{{viewer_hash}}">Raster</a>
{{/if}} {{/if}}
{{#if serving_data}} {{#if serving_data}}
<a class="btn" href="/styles/{{@key}}/?{{&../key_query_part}}vector{{viewer_hash}}">Vector</a> <a class="btn" href="{{baseURL}}/styles/{{@key}}/?{{&../key_query_part}}vector{{viewer_hash}}">Vector</a>
{{/if}} {{/if}}
</div> </div>
</div> </div>
@ -65,15 +65,15 @@
{{#each data}} {{#each data}}
<div class="item"> <div class="item">
{{#if thumbnail}} {{#if thumbnail}}
<img src="/data/{{@key}}/{{thumbnail}}{{&../key_query}}" alt="{{name}} preview" /> <img src="{{baseURL}}/data/{{@key}}/{{thumbnail}}{{&../key_query}}" alt="{{name}} preview" />
{{else}} {{else}}
<img src="/images/placeholder.png" alt="{{name}} preview" /> <img src="{{baseURL}}/images/placeholder.png" alt="{{name}} preview" />
{{/if}} {{/if}}
<div class="details"> <div class="details">
<h3>{{name}}</h3> <h3>{{name}}</h3>
<p class="identifier">identifier: {{@key}}{{#if formatted_filesize}} | size: {{formatted_filesize}}{{/if}} | type: {{#is_vector}}vector{{/is_vector}}{{^is_vector}}raster{{/is_vector}} data</p> <p class="identifier">identifier: {{@key}}{{#if formatted_filesize}} | size: {{formatted_filesize}}{{/if}} | type: {{#is_vector}}vector{{/is_vector}}{{^is_vector}}raster{{/is_vector}} data</p>
<p class="services"> <p class="services">
services: <a href="/data/{{@key}}.json{{&../key_query}}">TileJSON</a> services: <a href="{{baseURL}}/data/{{@key}}.json{{&../key_query}}">TileJSON</a>
{{#if wmts_link}} {{#if wmts_link}}
| <a href="{{&wmts_link}}">WMTS</a> | <a href="{{&wmts_link}}">WMTS</a>
{{/if}} {{/if}}
@ -85,10 +85,10 @@
</div> </div>
<div class="viewers"> <div class="viewers">
{{#is_vector}} {{#is_vector}}
<a class="btn" href="/data/{{@key}}/{{&../key_query}}{{viewer_hash}}">X-Ray view</a> <a class="btn" href="{{baseURL}}/data/{{@key}}/{{&../key_query}}{{viewer_hash}}">X-Ray view</a>
{{/is_vector}} {{/is_vector}}
{{^is_vector}} {{^is_vector}}
<a class="btn" href="/data/{{@key}}/{{&../key_query}}{{viewer_hash}}">Raster view</a> <a class="btn" href="{{baseURL}}/data/{{@key}}/{{&../key_query}}{{viewer_hash}}">Raster view</a>
{{/is_vector}} {{/is_vector}}
</div> </div>
</div> </div>
@ -96,7 +96,7 @@
</div> </div>
</section> </section>
<footer> <footer>
<a href="https://www.klokantech.com/" target="_blank"><img src="/images/klokantech.png" /></a> <a href="https://www.klokantech.com/" target="_blank"><img src="{{baseURL}}/images/klokantech.png" /></a>
<p> <p>
<a href="https://github.com/klokantech/tileserver-gl" target="_blank">Powered by TileServer GL ({{server_version}})</a> <a href="https://www.klokantech.com/" target="_blank">open-source project from Klokan Technologies GmbH.</a> <a href="https://github.com/klokantech/tileserver-gl" target="_blank">Powered by TileServer GL ({{server_version}})</a> <a href="https://www.klokantech.com/" target="_blank">open-source project from Klokan Technologies GmbH.</a>
</p> </p>

View file

@ -4,11 +4,11 @@
<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>
<link rel="stylesheet" type="text/css" href="/mapbox-gl.css{{&key_query}}" /> <link rel="stylesheet" type="text/css" href="{{baseURL}}/mapbox-gl.css{{&key_query}}" />
<script src="/mapbox-gl.js{{&key_query}}"></script> <script src="{{baseURL}}/mapbox-gl.js{{&key_query}}"></script>
<link rel="stylesheet" type="text/css" href="/mapbox.css{{&key_query}}" /> <link rel="stylesheet" type="text/css" href="/mapbox.css{{&key_query}}" />
<script src="/mapbox.js{{&key_query}}"></script> <script src="{{baseURL}}/mapbox.js{{&key_query}}"></script>
<script src="/leaflet-hash.js{{&key_query}}"></script> <script src="{{baseURL}}/leaflet-hash.js{{&key_query}}"></script>
<style> <style>
body { margin:0; padding:0; } body { margin:0; padding:0; }
#map { position:absolute; top:0; bottom:0; width:100%; } #map { position:absolute; top:0; bottom:0; width:100%; }
@ -26,12 +26,12 @@
if (preference == 'vector') { if (preference == 'vector') {
var map = new mapboxgl.Map({ var map = new mapboxgl.Map({
container: 'map', container: 'map',
style: '/styles/{{id}}.json{{&key_query}}', style: '{{baseURL}}/styles/{{id}}.json{{&key_query}}',
hash: true hash: true
}); });
map.addControl(new mapboxgl.Navigation()); map.addControl(new mapboxgl.Navigation());
} else { } else {
var map = L.mapbox.map('map', '/styles/{{id}}/rendered.json{{&key_query}}', { zoomControl: false }); var map = L.mapbox.map('map', '{{baseURL}}/styles/{{id}}/rendered.json{{&key_query}}', { zoomControl: false });
new L.Control.Zoom({ position: 'topright' }).addTo(map); new L.Control.Zoom({ position: 'topright' }).addTo(map);
setTimeout(function() { setTimeout(function() {
new L.Hash(map); new L.Hash(map);

View file

@ -13,6 +13,7 @@ module.exports = function(options, repo, params, id) {
var app = express().disable('x-powered-by'); var app = express().disable('x-powered-by');
var mbtilesFile = path.resolve(options.paths.mbtiles, params.mbtiles); var mbtilesFile = path.resolve(options.paths.mbtiles, params.mbtiles);
var baseURL = options.baseURL;
var tileJSON = { var tileJSON = {
'tiles': params.domains || options.domains 'tiles': params.domains || options.domains
}; };
@ -81,7 +82,7 @@ module.exports = function(options, repo, params, id) {
app.get('/' + id + '.json', function(req, res, next) { app.get('/' + id + '.json', function(req, res, next) {
var info = clone(tileJSON); var info = clone(tileJSON);
info.tiles = utils.getTileUrls(req, info.tiles, info.tiles = utils.getTileUrls(req, info.tiles,
'data/' + id, info.format); 'data/' + id, info.format, baseURL);
return res.send(info); return res.send(info);
}); });

View file

@ -42,6 +42,7 @@ module.exports = function(options, repo, params, id, dataResolver) {
var lastModified = new Date().toUTCString(); var lastModified = new Date().toUTCString();
var rootPath = options.paths.root; var rootPath = options.paths.root;
var baseURL = options.baseURL;
var styleFile = params.style; var styleFile = params.style;
var map = { var map = {
@ -564,7 +565,7 @@ module.exports = function(options, repo, params, id, dataResolver) {
app.get('/rendered.json', function(req, res, next) { app.get('/rendered.json', function(req, res, next) {
var info = clone(tileJSON); var info = clone(tileJSON);
info.tiles = utils.getTileUrls(req, info.tiles, info.tiles = utils.getTileUrls(req, info.tiles,
'styles/' + id + '/rendered', info.format); 'styles/' + id + '/rendered', info.format, baseURL);
return res.send(info); return res.send(info);
}); });

View file

@ -12,6 +12,8 @@ module.exports = function(options, repo, params, id, reportTiles, reportFont) {
var styleFile = path.join(options.paths.styles, params.style); var styleFile = path.join(options.paths.styles, params.style);
var baseURL = options.baseURL;
var styleJSON = clone(require(styleFile)); var styleJSON = clone(require(styleFile));
Object.keys(styleJSON.sources).forEach(function(name) { Object.keys(styleJSON.sources).forEach(function(name) {
var source = styleJSON.sources[name]; var source = styleJSON.sources[name];
@ -57,8 +59,8 @@ module.exports = function(options, repo, params, id, reportTiles, reportFont) {
if (!opt_nokey && req.query.key) { if (!opt_nokey && req.query.key) {
query = '?key=' + req.query.key; query = '?key=' + req.query.key;
} }
return url.replace( return url.replace('local://',
'local://', req.protocol + '://' + req.headers.host + '/') + query; (baseURL ? baseURL : req.protocol + '://' + req.headers.host) + '/') + query;
}; };
var styleJSON_ = clone(styleJSON); var styleJSON_ = clone(styleJSON);

View file

@ -69,6 +69,8 @@ module.exports = function(opts, callback) {
} }
var options = config.options || {}; var options = config.options || {};
var baseURL = options.baseURL;
var paths = options.paths || {}; var paths = options.paths || {};
options.paths = paths; options.paths = paths;
paths.root = path.resolve( paths.root = path.resolve(
@ -165,7 +167,7 @@ module.exports = function(opts, callback) {
version: styleJSON.version, version: styleJSON.version,
name: styleJSON.name, name: styleJSON.name,
id: id, id: id,
url: req.protocol + '://' + req.headers.host + url: (baseURL ? baseURL : req.protocol + '://' + req.headers.host) +
'/styles/' + id + '.json' + query '/styles/' + id + '.json' + query
}); });
}); });
@ -176,7 +178,7 @@ module.exports = function(opts, callback) {
Object.keys(serving[type]).forEach(function(id) { Object.keys(serving[type]).forEach(function(id) {
var info = clone(serving[type][id]); var info = clone(serving[type][id]);
info.tiles = utils.getTileUrls(req, info.tiles, info.tiles = utils.getTileUrls(req, info.tiles,
type + '/' + id, info.format); type + '/' + id, info.format, baseURL);
arr.push(info); arr.push(info);
}); });
return arr; return arr;
@ -224,6 +226,7 @@ module.exports = function(opts, callback) {
serveTemplate('/$', 'index', function(req) { serveTemplate('/$', 'index', function(req) {
var styles = clone(config.styles || {}); var styles = clone(config.styles || {});
Object.keys(styles).forEach(function(id) { Object.keys(styles).forEach(function(id) {
var style = styles[id]; var style = styles[id];
style.name = (serving.styles[id] || serving.rendered[id] || {}).name; style.name = (serving.styles[id] || serving.rendered[id] || {}).name;
@ -247,10 +250,12 @@ module.exports = function(opts, callback) {
base64url('http://' + req.headers.host + base64url('http://' + req.headers.host +
'/styles/' + id + '/rendered.json' + query) + '/wmts'; '/styles/' + id + '/rendered.json' + query) + '/wmts';
var tiles = utils.getTileUrls( var tiles = utils.getTileUrls(
req, style.serving_rendered.tiles, req, style.serving_rendered.tiles,
'styles/' + id + '/rendered', style.serving_rendered.format); 'styles/' + id + '/rendered', style.serving_rendered.format, baseURL);
style.xyz_link = tiles[0]; style.xyz_link = tiles[0];
style.baseURL = baseURL;
} }
}); });
var data = clone(serving.data || {}); var data = clone(serving.data || {});
@ -277,7 +282,7 @@ module.exports = function(opts, callback) {
'/data/' + id + '.json' + query) + '/wmts'; '/data/' + id + '.json' + query) + '/wmts';
var tiles = utils.getTileUrls( var tiles = utils.getTileUrls(
req, data_.tiles, 'data/' + id, data_.format); req, data_.tiles, 'data/' + id, data_.format, baseURL);
data_.xyz_link = tiles[0]; data_.xyz_link = tiles[0];
} }
if (data_.filesize) { if (data_.filesize) {
@ -292,11 +297,13 @@ module.exports = function(opts, callback) {
size /= 1024; size /= 1024;
} }
data_.formatted_filesize = size.toFixed(2) + ' ' + suffix; data_.formatted_filesize = size.toFixed(2) + ' ' + suffix;
data_.baseURL = baseURL;
} }
}); });
return { return {
styles: styles, styles: styles,
data: data data: data,
baseURL: baseURL
}; };
}); });
@ -310,6 +317,7 @@ module.exports = function(opts, callback) {
style.name = (serving.styles[id] || serving.rendered[id]).name; style.name = (serving.styles[id] || serving.rendered[id]).name;
style.serving_data = serving.styles[id]; style.serving_data = serving.styles[id];
style.serving_rendered = serving.rendered[id]; style.serving_rendered = serving.rendered[id];
style.baseURL = baseURL;
return style; return style;
}); });
@ -327,6 +335,8 @@ module.exports = function(opts, callback) {
} }
data.id = id; data.id = id;
data.is_vector = data.format == 'pbf'; data.is_vector = data.format == 'pbf';
data.baseURL = baseURL;
return data; return data;
}); });

View file

@ -6,20 +6,24 @@ var async = require('async'),
var glyphCompose = require('glyph-pbf-composite'); var glyphCompose = require('glyph-pbf-composite');
module.exports.getTileUrls = function(req, domains, path, format) { module.exports.getTileUrls = function(req, domains, path, format, baseURL) {
var key = req.query.key;
var query = (key && key.length > 0) ? ('?key=' + key) : '';
if (baseURL) {
return [baseURL + '/' + path + '/{z}/{x}/{y}.' + format + query]
}
if (domains) { if (domains) {
if (domains.constructor === String && domains.length > 0) { if (domains.constructor === String && domains.length > 0) {
domains = domains.split(','); domains = domains.split(',');
} }
} }
if (!domains || domains.length == 0) { if (!domains || domains.length == 0) {
domains = [req.headers.host]; domains = [req.headers.host];
} }
var key = req.query.key;
var query = (key && key.length > 0) ? ('?key=' + key) : '';
var uris = []; var uris = [];
domains.forEach(function(domain) { domains.forEach(function(domain) {
uris.push(req.protocol + '://' + domain + '/' + path + uris.push(req.protocol + '://' + domain + '/' + path +