Compare commits

...

12 Commits

Author SHA1 Message Date
Petr Sloup
e1654a51de Update package version to 1.5.0 2017-03-29 15:46:30 +02:00
Petr Sloup
5372bab6c5 Update dependencies 2017-03-29 15:45:32 +02:00
Petr Sloup
6a960e8593 Remove optional dependencies from package.json to avoid warnings 2017-03-17 10:42:25 +01:00
Petr Sloup
1577cfa54a Update dependencies 2017-03-15 17:20:55 +01:00
Petr Sloup
640038a115 Add support for watermarks (close #130) 2017-03-15 17:06:26 +01:00
Petr Sloup
49a8562441 Support for proj4 string in mbtiles metadata (for static maps) (close #127) 2017-03-15 16:45:26 +01:00
Petr Sloup
1e402ed207 Add possibility to change the front page (close #128) 2017-03-15 15:50:58 +01:00
Petr Sloup
f8949c1aa9 Configurable scale factors (close #121)
Also changes default maximum from `4x` to `3x`
2017-03-15 12:09:18 +01:00
Petr Sloup
7b952ee5c0 Do not add style parameter when not needed (close #134) 2017-03-15 11:39:21 +01:00
Petr Sloup
0673c8990a Add option to disable static maps (close #129) 2017-03-14 16:12:19 +01:00
Petr Sloup
37386bfb29 Hide empty headers on index (close #125) 2017-03-14 16:02:54 +01:00
Petr Sloup
b93bc5fadc Support for handling relative subdomain patterns 2017-03-14 15:50:14 +01:00
9 changed files with 311 additions and 205 deletions

View File

@@ -25,9 +25,11 @@ Example::
"pngQuantization": false,
"png": 90
},
"maxScaleFactor": 3,
"maxSize": 2048,
"pbfAlias": "pbf",
"serveAllFonts": false
"serveAllFonts": false,
"serveStaticMaps": true
},
"styles": {
"basic": {
@@ -68,6 +70,14 @@ 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.
``frontPage``
-----------------
Path to the html (relative to ``root`` path) to use as a front page.
Use ``true`` (or nothing) to serve the default TileServer GL front page with list of styles and data.
Use ``false`` to disable the front page altogether (404).
``formatQuality``
-----------------
@@ -75,10 +85,26 @@ Quality of the compression of individual image formats. [0-100]
The value for ``png`` is only used when ``pngQuantization`` is ``true``.
``maxScaleFactor``
-----------
Maximum scale factor to allow in raster tile and static maps requests (e.g. ``@3x`` suffix).
Also see ``maxSize`` below.
Default value is ``3``, maximum ``9``.
``maxSize``
-----------
Maximum image side length to be allowed to be rendered (including scale factor). Default is ``2048``.
Maximum image side length to be allowed to be rendered (including scale factor).
Be careful when changing this value since there are hardware limits that need to be considered.
Default is ``2048``.
``watermark``
-----------
Optional string to be rendered into the raster tiles (and static maps) as watermark (bottom-left corner).
Can be used for hard-coding attributions etc. (can also be specified per-style).
Not used by default.
``styles``
==========

View File

@@ -1,6 +1,6 @@
{
"name": "tileserver-gl",
"version": "1.4.1",
"version": "1.5.0",
"description": "Map tile server for JSON GL styles - vector and server side generated raster tiles",
"main": "src/main.js",
"bin": "src/main.js",
@@ -19,31 +19,29 @@
"test": "mocha test/**.js"
},
"dependencies": {
"async": "2.1.4",
"async": "2.2.0",
"advanced-pool": "0.3.2",
"base64url": "2.0.0",
"canvas": "1.6.2",
"clone": "2.1.0",
"canvas": "1.6.5",
"clone": "2.1.1",
"color": "1.0.3",
"cors": "2.8.1",
"express": "4.14.1",
"cors": "2.8.2",
"express": "4.15.2",
"glyph-pbf-composite": "0.0.2",
"handlebars": "4.0.6",
"mbtiles": "0.9.0",
"morgan": "1.7.0",
"morgan": "1.8.1",
"node-pngquant-native": "1.0.4",
"nomnom": "1.8.1",
"pbf": "3.0.5",
"request": "2.79.0",
"sharp": "0.17.1",
"tileserver-gl-styles": "1.1.0",
"proj4": "2.4.3",
"request": "2.81.0",
"sharp": "0.17.2",
"tileserver-gl-styles": "1.1.1",
"vector-tile": "1.3.0",
"@mapbox/mapbox-gl-native": "3.4.4",
"@mapbox/sphericalmercator": "1.0.5"
},
"optionalDependencies": {
"tileshrink-gl": "./plugins/tileshrink-gl"
},
"devDependencies": {
"should": "^11.2.0",
"mocha": "^3.2.0",

View File

@@ -19,85 +19,89 @@
<section>
<h1 class="title {{#if is_light}}light{{/if}}"><img src="/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="box-header">Styles</h2>
<div class="box">
{{#each styles}}
<div class="item">
{{#if thumbnail}}
<img src="/styles/{{@key}}/rendered/{{thumbnail}}{{&../key_query}}" alt="{{name}} preview" />
{{else}}
<img src="/images/placeholder.png" alt="{{name}} preview" />
{{/if}}
<div class="details">
<h3>{{name}}</h3>
<p class="identifier">identifier: {{@key}}</p>
<p class="services">
services:
{{#if styles}}
<h2 class="box-header">Styles</h2>
<div class="box">
{{#each styles}}
<div class="item">
{{#if thumbnail}}
<img src="/styles/{{@key}}/rendered/{{thumbnail}}{{&../key_query}}" alt="{{name}} preview" />
{{else}}
<img src="/images/placeholder.png" alt="{{name}} preview" />
{{/if}}
<div class="details">
<h3>{{name}}</h3>
<p class="identifier">identifier: {{@key}}</p>
<p class="services">
services:
{{#if serving_data}}
<a href="/styles/{{@key}}.json{{&../key_query}}">GL Style</a>
{{/if}}
{{#if serving_rendered}}
{{#if serving_data}}| {{/if}}<a href="/styles/{{@key}}/rendered.json{{&../key_query}}">TileJSON</a>
{{/if}}
{{#if wmts_link}}
| <a href="{{&wmts_link}}">WMTS</a>
{{/if}}
{{#if xyz_link}}
| <a href="#" onclick="return toggle_xyz('xyz_style_{{@key}}');">XYZ</a>
<input id="xyz_style_{{@key}}" type="text" value="{{&xyz_link}}" style="display:none;" />
{{/if}}
</p>
</div>
<div class="viewers">
{{#if serving_data}}
<a href="/styles/{{@key}}.json{{&../key_query}}">GL Style</a>
{{#if serving_rendered}}
<a class="btn" href="/styles/{{@key}}/{{&../key_query}}{{viewer_hash}}">Viewer</a>
{{/if}}
{{/if}}
{{#if serving_rendered}}
{{#if serving_data}}| {{/if}}<a href="/styles/{{@key}}/rendered.json{{&../key_query}}">TileJSON</a>
<a class="btn" href="/styles/{{@key}}/?{{&../key_query_part}}raster{{viewer_hash}}">Raster</a>
{{/if}}
{{#if wmts_link}}
| <a href="{{&wmts_link}}">WMTS</a>
{{#if serving_data}}
<a class="btn" href="/styles/{{@key}}/?{{&../key_query_part}}vector{{viewer_hash}}">Vector</a>
{{/if}}
{{#if xyz_link}}
| <a href="#" onclick="return toggle_xyz('xyz_style_{{@key}}');">XYZ</a>
<input id="xyz_style_{{@key}}" type="text" value="{{&xyz_link}}" style="display:none;" />
{{/if}}
</p>
</div>
<div class="viewers">
{{#if serving_data}}
{{#if serving_rendered}}
<a class="btn" href="/styles/{{@key}}/{{&../key_query}}{{viewer_hash}}">Viewer</a>
{{/if}}
{{/if}}
{{#if serving_rendered}}
<a class="btn" href="/styles/{{@key}}/?{{&../key_query_part}}raster{{viewer_hash}}">Raster</a>
{{/if}}
{{#if serving_data}}
<a class="btn" href="/styles/{{@key}}/?{{&../key_query_part}}vector{{viewer_hash}}">Vector</a>
{{/if}}
</div>
</div>
{{/each}}
</div>
{{/each}}
</div>
<h2 class="box-header">Data</h2>
<div class="box">
{{#each data}}
<div class="item">
{{#if thumbnail}}
<img src="/data/{{@key}}/{{thumbnail}}{{&../key_query}}" alt="{{name}} preview" />
{{else}}
<img src="/images/placeholder.png" alt="{{name}} preview" />
{{/if}}
<div class="details">
<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="services">
services: <a href="/data/{{@key}}.json{{&../key_query}}">TileJSON</a>
{{#if wmts_link}}
| <a href="{{&wmts_link}}">WMTS</a>
{{/if}}
{{#if xyz_link}}
| <a href="#" onclick="return toggle_xyz('xyz_data_{{@key}}');">XYZ</a>
<input id="xyz_data_{{@key}}" type="text" value="{{&xyz_link}}" style="display:none;" />
{{/if}}
</p>
</div>
<div class="viewers">
{{#is_vector}}
<a class="btn" href="/data/{{@key}}/{{&../key_query}}{{viewer_hash}}">Inspect</a>
{{/is_vector}}
{{^is_vector}}
<a class="btn" href="/data/{{@key}}/{{&../key_query}}{{viewer_hash}}">View</a>
{{/is_vector}}
{{/if}}
{{#if data}}
<h2 class="box-header">Data</h2>
<div class="box">
{{#each data}}
<div class="item">
{{#if thumbnail}}
<img src="/data/{{@key}}/{{thumbnail}}{{&../key_query}}" alt="{{name}} preview" />
{{else}}
<img src="/images/placeholder.png" alt="{{name}} preview" />
{{/if}}
<div class="details">
<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="services">
services: <a href="/data/{{@key}}.json{{&../key_query}}">TileJSON</a>
{{#if wmts_link}}
| <a href="{{&wmts_link}}">WMTS</a>
{{/if}}
{{#if xyz_link}}
| <a href="#" onclick="return toggle_xyz('xyz_data_{{@key}}');">XYZ</a>
<input id="xyz_data_{{@key}}" type="text" value="{{&xyz_link}}" style="display:none;" />
{{/if}}
</p>
</div>
<div class="viewers">
{{#is_vector}}
<a class="btn" href="/data/{{@key}}/{{&../key_query}}{{viewer_hash}}">Inspect</a>
{{/is_vector}}
{{^is_vector}}
<a class="btn" href="/data/{{@key}}/{{&../key_query}}{{viewer_hash}}">View</a>
{{/is_vector}}
</div>
</div>
{{/each}}
</div>
{{/each}}
</div>
{{/if}}
</section>
<footer>
<a href="https://www.klokantech.com/" target="_blank"><img src="/images/klokantech.png" /></a>

View File

@@ -13,6 +13,7 @@ var clone = require('clone'),
var tileshrinkGl;
try {
tileshrinkGl = require('tileshrink-gl');
global.addStyleParam = true;
} catch (e) {}
var utils = require('./utils');

View File

@@ -19,12 +19,12 @@ var Canvas = require('canvas'),
mbgl = require('@mapbox/mapbox-gl-native'),
mbtiles = require('mbtiles'),
pngquant = require('node-pngquant-native'),
proj4 = require('proj4'),
request = require('request');
var utils = require('./utils');
var FLOAT_PATTERN = '[+-]?(?:\\d+|\\d+\.?\\d+)';
var SCALE_PATTERN = '@[234]x';
var getScale = function(scale) {
return (scale || '@1x').slice(1, 2) | 0;
@@ -39,10 +39,19 @@ mbgl.on('message', function(e) {
module.exports = function(options, repo, params, id, dataResolver) {
var app = express().disable('x-powered-by');
var maxScaleFactor = Math.min(Math.floor(options.maxScaleFactor || 3), 9);
var scalePattern = '';
for (var i = 2; i <= maxScaleFactor; i++) {
scalePattern += i.toFixed();
}
scalePattern = '@[' + scalePattern + ']x';
var lastModified = new Date().toUTCString();
var rootPath = options.paths.root;
var watermark = params.watermark || options.watermark;
var styleFile = params.style;
var map = {
renderers: [],
@@ -186,6 +195,8 @@ module.exports = function(options, repo, params, id, dataResolver) {
tileJSON.tiles = params.domains || options.domains;
utils.fixTileJSONCenter(tileJSON);
var dataProjWGStoInternalWGS = null;
var queue = [];
Object.keys(styleJSON.sources).forEach(function(name) {
var source = styleJSON.sources[name];
@@ -223,6 +234,16 @@ module.exports = function(options, repo, params, id, dataResolver) {
if (err) {
console.error(err);
}
if (!dataProjWGStoInternalWGS && info.proj4) {
// how to do this for multiple sources with different proj4 defs?
var to3857 = proj4('EPSG:3857');
var toDataProj = proj4(info.proj4);
dataProjWGStoInternalWGS = function(xy) {
return to3857.inverse(toDataProj.forward(xy));
};
}
var type = source.type;
Object.assign(source, info);
source.type = type;
@@ -267,16 +288,24 @@ module.exports = function(options, repo, params, id, dataResolver) {
async.parallel(queue, function(err, results) {
// TODO: make pool sizes configurable
map.renderers[1] = createPool(1, 4, 16);
map.renderers[2] = createPool(2, 2, 8);
map.renderers[3] = createPool(3, 2, 4);
map.renderers[4] = createPool(4, 2, 4);
for (var s = 1; s <= maxScaleFactor; s++) {
var minPoolSize = 2;
// standard and @2x tiles are much more usual -> create larger pools
if (s <= 2) {
minPoolSize *= 2;
if (s <= 1) {
minPoolSize *= 2;
}
}
map.renderers[s] = createPool(s, minPoolSize, 2 * minPoolSize);
}
});
repo[id] = tileJSON;
var tilePattern = '/rendered/:z(\\d+)/:x(\\d+)/:y(\\d+)' +
':scale(' + SCALE_PATTERN + ')?\.:format([\\w]+)';
':scale(' + scalePattern + ')?\.:format([\\w]+)';
var respondImage = function(z, lon, lat, bearing, pitch,
width, height, scale, format, res, next,
@@ -330,6 +359,19 @@ module.exports = function(options, repo, params, id, dataResolver) {
if (opt_overlay) {
image.overlayWith(opt_overlay);
}
if (watermark) {
var canvas = new Canvas(scale * width, scale * height);
var ctx = canvas.getContext('2d');
ctx.scale(scale, scale);
ctx.font = '10px sans-serif';
ctx.strokeWidth = '1px';
ctx.strokeStyle = 'rgba(255,255,255,.4)';
ctx.strokeText(watermark, 5, height - 5);
ctx.fillStyle = 'rgba(0,0,0,.4)';
ctx.fillText(watermark, 5, height - 5);
image.overlayWith(canvas.toBuffer());
}
var formatQuality = (params.formatQuality || {})[format] ||
(options.formatQuality || {})[format];
@@ -392,17 +434,22 @@ module.exports = function(options, repo, params, id, dataResolver) {
tileSize, tileSize, scale, format, res, next);
});
var extractPathFromQuery = function(query) {
var extractPathFromQuery = function(query, transformer) {
var pathParts = (query.path || '').split('|');
var path = [];
pathParts.forEach(function(pair) {
var pairParts = pair.split(',');
if (pairParts.length == 2) {
var pair;
if (query.latlng == '1' || query.latlng == 'true') {
path.push([+(pairParts[1]), +(pairParts[0])]);
pair = [+(pairParts[1]), +(pairParts[0])];
} else {
path.push([+(pairParts[0]), +(pairParts[1])]);
pair = [+(pairParts[0]), +(pairParts[1])];
}
if (transformer) {
pair = transformer(pair);
}
path.push(pair);
}
});
return path;
@@ -474,121 +521,126 @@ module.exports = function(options, repo, params, id, dataResolver) {
return z;
};
var staticPattern =
'/static/:raw(raw)?/%s/:width(\\d+)x:height(\\d+)' +
':scale(' + SCALE_PATTERN + ')?\.:format([\\w]+)';
if (options.serveStaticMaps !== false) {
var staticPattern =
'/static/:raw(raw)?/%s/:width(\\d+)x:height(\\d+)' +
':scale(' + scalePattern + ')?\.:format([\\w]+)';
var centerPattern =
util.format(':x(%s),:y(%s),:z(%s)(@:bearing(%s)(,:pitch(%s))?)?',
FLOAT_PATTERN, FLOAT_PATTERN, FLOAT_PATTERN,
FLOAT_PATTERN, FLOAT_PATTERN);
var centerPattern =
util.format(':x(%s),:y(%s),:z(%s)(@:bearing(%s)(,:pitch(%s))?)?',
FLOAT_PATTERN, FLOAT_PATTERN, FLOAT_PATTERN,
FLOAT_PATTERN, FLOAT_PATTERN);
app.get(util.format(staticPattern, centerPattern), function(req, res, next) {
var raw = req.params.raw;
var z = +req.params.z,
x = +req.params.x,
y = +req.params.y,
bearing = +(req.params.bearing || '0'),
pitch = +(req.params.pitch || '0'),
w = req.params.width | 0,
h = req.params.height | 0,
scale = getScale(req.params.scale),
format = req.params.format;
app.get(util.format(staticPattern, centerPattern), function(req, res, next) {
var raw = req.params.raw;
var z = +req.params.z,
x = +req.params.x,
y = +req.params.y,
bearing = +(req.params.bearing || '0'),
pitch = +(req.params.pitch || '0'),
w = req.params.width | 0,
h = req.params.height | 0,
scale = getScale(req.params.scale),
format = req.params.format;
if (z < 0) {
return res.status(404).send('Invalid zoom');
}
if (z < 0) {
return res.status(404).send('Invalid zoom');
}
if (raw) {
var ll = mercator.inverse([x, y]);
x = ll[0];
y = ll[1];
}
var transformer = raw ?
mercator.inverse.bind(mercator) : dataProjWGStoInternalWGS;
var path = extractPathFromQuery(req.query);
var overlay = renderOverlay(z, x, y, bearing, pitch, w, h, scale,
path, req.query);
if (transformer) {
var ll = transformer([x, y]);
x = ll[0];
y = ll[1];
}
return respondImage(z, x, y, bearing, pitch, w, h, scale, format,
res, next, overlay);
});
var path = extractPathFromQuery(req.query, transformer);
var overlay = renderOverlay(z, x, y, bearing, pitch, w, h, scale,
path, req.query);
var boundsPattern =
util.format(':minx(%s),:miny(%s),:maxx(%s),:maxy(%s)',
FLOAT_PATTERN, FLOAT_PATTERN, FLOAT_PATTERN, FLOAT_PATTERN);
app.get(util.format(staticPattern, boundsPattern), function(req, res, next) {
var raw = req.params.raw;
var bbox = [+req.params.minx, +req.params.miny,
+req.params.maxx, +req.params.maxy];
if (raw) {
var minCorner = mercator.inverse(bbox.slice(0, 2));
var maxCorner = mercator.inverse(bbox.slice(2));
bbox[0] = minCorner[0];
bbox[1] = minCorner[1];
bbox[2] = maxCorner[0];
bbox[3] = maxCorner[1];
}
var w = req.params.width | 0,
h = req.params.height | 0,
scale = getScale(req.params.scale),
format = req.params.format;
var z = calcZForBBox(bbox, w, h, req.query),
x = (bbox[0] + bbox[2]) / 2,
y = (bbox[1] + bbox[3]) / 2,
bearing = 0,
pitch = 0;
var path = extractPathFromQuery(req.query);
var overlay = renderOverlay(z, x, y, bearing, pitch, w, h, scale,
path, req.query);
return respondImage(z, x, y, bearing, pitch, w, h, scale, format,
res, next, overlay);
});
var autoPattern = 'auto';
app.get(util.format(staticPattern, autoPattern), function(req, res, next) {
var path = extractPathFromQuery(req.query);
if (path.length < 2) {
return res.status(400).send('Invalid path');
}
var raw = req.params.raw;
var w = req.params.width | 0,
h = req.params.height | 0,
bearing = 0,
pitch = 0,
scale = getScale(req.params.scale),
format = req.params.format;
var bbox = [Infinity, Infinity, -Infinity, -Infinity];
path.forEach(function(pair) {
bbox[0] = Math.min(bbox[0], pair[0]);
bbox[1] = Math.min(bbox[1], pair[1]);
bbox[2] = Math.max(bbox[2], pair[0]);
bbox[3] = Math.max(bbox[3], pair[1]);
return respondImage(z, x, y, bearing, pitch, w, h, scale, format,
res, next, overlay);
});
var z = calcZForBBox(bbox, w, h, req.query),
x = (bbox[0] + bbox[2]) / 2,
y = (bbox[1] + bbox[3]) / 2;
var boundsPattern =
util.format(':minx(%s),:miny(%s),:maxx(%s),:maxy(%s)',
FLOAT_PATTERN, FLOAT_PATTERN, FLOAT_PATTERN, FLOAT_PATTERN);
if (raw) {
var ll = mercator.inverse([x, y]);
x = ll[0];
y = ll[1];
}
app.get(util.format(staticPattern, boundsPattern), function(req, res, next) {
var raw = req.params.raw;
var bbox = [+req.params.minx, +req.params.miny,
+req.params.maxx, +req.params.maxy];
var overlay = renderOverlay(z, x, y, bearing, pitch, w, h, scale,
path, req.query);
var transformer = raw ?
mercator.inverse.bind(mercator) : dataProjWGStoInternalWGS;
return respondImage(z, x, y, bearing, pitch, w, h, scale, format,
res, next, overlay);
});
if (transformer) {
var minCorner = transformer(bbox.slice(0, 2));
var maxCorner = transformer(bbox.slice(2));
bbox[0] = minCorner[0];
bbox[1] = minCorner[1];
bbox[2] = maxCorner[0];
bbox[3] = maxCorner[1];
}
var w = req.params.width | 0,
h = req.params.height | 0,
scale = getScale(req.params.scale),
format = req.params.format;
var z = calcZForBBox(bbox, w, h, req.query),
x = (bbox[0] + bbox[2]) / 2,
y = (bbox[1] + bbox[3]) / 2,
bearing = 0,
pitch = 0;
var path = extractPathFromQuery(req.query, transformer);
var overlay = renderOverlay(z, x, y, bearing, pitch, w, h, scale,
path, req.query);
return respondImage(z, x, y, bearing, pitch, w, h, scale, format,
res, next, overlay);
});
var autoPattern = 'auto';
app.get(util.format(staticPattern, autoPattern), function(req, res, next) {
var raw = req.params.raw;
var w = req.params.width | 0,
h = req.params.height | 0,
bearing = 0,
pitch = 0,
scale = getScale(req.params.scale),
format = req.params.format;
var transformer = raw ?
mercator.inverse.bind(mercator) : dataProjWGStoInternalWGS;
var path = extractPathFromQuery(req.query, transformer);
if (path.length < 2) {
return res.status(400).send('Invalid path');
}
var bbox = [Infinity, Infinity, -Infinity, -Infinity];
path.forEach(function(pair) {
bbox[0] = Math.min(bbox[0], pair[0]);
bbox[1] = Math.min(bbox[1], pair[1]);
bbox[2] = Math.max(bbox[2], pair[0]);
bbox[3] = Math.max(bbox[3], pair[1]);
});
var z = calcZForBBox(bbox, w, h, req.query),
x = (bbox[0] + bbox[2]) / 2,
y = (bbox[1] + bbox[3]) / 2;
var overlay = renderOverlay(z, x, y, bearing, pitch, w, h, scale,
path, req.query);
return respondImage(z, x, y, bearing, pitch, w, h, scale, format,
res, next, overlay);
});
}
app.get('/rendered.json', function(req, res, next) {
var info = clone(tileJSON);

View File

@@ -68,7 +68,7 @@ module.exports = function(options, repo, params, id, reportTiles, reportFont) {
return url;
}
var queryParams = [];
if (!opt_nostyle) {
if (!opt_nostyle && global.addStyleParam) {
queryParams.push('style=' + id);
}
if (!opt_nokey && req.query.key) {

View File

@@ -209,14 +209,23 @@ module.exports = function(opts, callback) {
app.use('/', express.static(path.join(__dirname, '../public/resources')));
var templates = path.join(__dirname, '../public/templates');
var serveTemplate = function(path, template, dataGetter) {
fs.readFile(templates + '/' + template + '.tmpl', function(err, content) {
var serveTemplate = function(urlPath, template, dataGetter) {
var templateFile = templates + '/' + template + '.tmpl';
if (template == 'index') {
if (options.frontPage === false) {
return;
} else if (options.frontPage &&
options.frontPage.constructor === String) {
templateFile = path.resolve(paths.root, options.frontPage);
}
}
fs.readFile(templateFile, function(err, content) {
if (err) {
console.log('Template not found:', err);
console.error('Template not found:', err);
}
var compiled = handlebars.compile(content.toString());
app.use(path, function(req, res, next) {
app.use(urlPath, function(req, res, next) {
var data = {};
if (dataGetter) {
data = dataGetter(req);
@@ -309,8 +318,8 @@ module.exports = function(opts, callback) {
}
});
return {
styles: styles,
data: data
styles: Object.keys(styles).length ? styles : null,
data: Object.keys(data).length ? data : null
};
});

View File

@@ -13,6 +13,23 @@ module.exports.getTileUrls = function(req, domains, path, format, aliases) {
if (domains.constructor === String && domains.length > 0) {
domains = domains.split(',');
}
var host = req.headers.host;
var hostParts = host.split('.');
var relativeSubdomainsUsable = hostParts.length > 1 &&
!/^([0-9]{1,3}\.){3}[0-9]{1,3}(\:[0-9]+)?$/.test(host);
var newDomains = [];
domains.forEach(function(domain) {
if (domain.indexOf('*') !== -1) {
if (relativeSubdomainsUsable) {
var newParts = hostParts.slice(1);
newParts.unshift(domain.replace('*', hostParts[0]));
newDomains.push(newParts.join('.'));
}
} else {
newDomains.push(domain);
}
});
domains = newDomains;
}
if (!domains || domains.length == 0) {
domains = [req.headers.host];

View File

@@ -26,7 +26,6 @@ describe('Raster tiles', function() {
testTile(prefix, 0, 0, 0, 'png', 200, 2);
testTile(prefix, 0, 0, 0, 'png', 200, 3);
testTile(prefix, 2, 1, 1, 'png', 200, 3);
testTile(prefix, 0, 0, 0, 'png', 200, 4);
});
});