Skip to content

Commit

Permalink
feat(url): add sub-domains handling in url construction
Browse files Browse the repository at this point in the history
Solves #942
  • Loading branch information
zarov committed Jul 29, 2019
1 parent fd8c61d commit 5638615
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 32 deletions.
67 changes: 45 additions & 22 deletions src/Provider/URLBuilder.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,37 @@
import Extent from 'Core/Geographic/Extent';

const extent = new Extent('EPSG:4326', [0, 0, 0, 0]);

let subDomainsCount = 0;
function subDomains(url) {
const subDomainsPtrn = /\$\{u:([\w-_.|]+)\}/.exec(url);

if (!subDomainsPtrn) {
return url;
}

const subDomainsList = subDomainsPtrn[1].split('|');

return url.replace(subDomainsPtrn[0], subDomainsList[(subDomainsCount++) % subDomainsList.length]);
}

/**
* This module performs basic operations around urls, to replace some elements
* in it by coordinates or other things.
*
* In an url, it is also possible to specify subdomains alternatives using the
* `${u:a|b|c}` pattern, by separating differents options using `|`. It will go
* through the following alternative each time (no random). For example
* `https://${u:xyz.org|yzx.org|zxy.org}/${z}/${x}/${y}.png` or
* `https://${u:a|b|c}.tile.openstreetmap.org/${z}/${x}/${y}.png`.
*
* @module URLBuilder
*/
export default {
/**
* Builds an URL knowing the coordinates and the layer to query.
* Builds an URL knowing the coordinates and the source to query.
* <br><br>
* The layer object needs to have an url property, which should have some
* The source object needs to have an url property, which should have some
* specific strings that will be replaced by coordinates.
* <ul>
* <li>`${x}` or `%COL` will be replaced by `coords.col`</li>
Expand All @@ -18,71 +41,71 @@ export default {
*
* @example
* coords = new Coordinates('WMTS:WGS84', 12, 1410, 2072);
* layer.url = 'http://server.geo/wmts/SERVICE=WMTS&TILEMATRIX=%TILEMATRIX&TILEROW=%ROW&TILECOL=%COL';
* url = URLBuilder.xyz(coords, layer);
* source.url = 'http://server.geo/wmts/SERVICE=WMTS&TILEMATRIX=%TILEMATRIX&TILEROW=%ROW&TILECOL=%COL';
* url = URLBuilder.xyz(coords, source);
*
* // The resulting url is:
* // http://server.geo/wmts/SERVICE=WMTS&TILEMATRIX=12&TILEROW=1410&TILECOL=2072;
*
* @example
* coords = new Extent('TMS', 15, 2142, 3412);
* layer.url = 'http://server.geo/tms/${z}/${y}/${x}.jpg';
* url = URLBuilder.xyz(coords, layer);
* source.url = 'http://server.geo/tms/${z}/${y}/${x}.jpg';
* url = URLBuilder.xyz(coords, source);
*
* // The resulting url is:
* // http://server.geo/tms/15/2142/3412.jpg;
*
* @param {Extent} coords - the coordinates
* @param {Layer} layer
* @param {Source} source
*
* @return {string} the formed url
*/
xyz: function xyz(coords, layer) {
return layer.url.replace(/(\$\{z\}|%TILEMATRIX)/, coords.zoom)
xyz: function xyz(coords, source) {
return subDomains(source.url.replace(/(\$\{z\}|%TILEMATRIX)/, coords.zoom)
.replace(/(\$\{y\}|%ROW)/, coords.row)
.replace(/(\$\{x\}|%COL)/, coords.col);
.replace(/(\$\{x\}|%COL)/, coords.col));
},

/**
* Builds an URL knowing the bounding box and the layer to query.
* Builds an URL knowing the bounding box and the source to query.
* <br><br>
* The layer object needs to have an url property, which should have the
* The source object needs to have an url property, which should have the
* string `%bbox` in it. This string will be replaced by the four cardinal
* points composing the bounding box.
* <br><br>
* Order of the points can be specified in the `axisOrder` property in
* layer, using the letters `w, s, e, n` respectively for `WEST, SOUTH,
* source, using the letters `w, s, e, n` respectively for `WEST, SOUTH,
* EAST, NORTH`. The default order is `wsen`.
*
* @example
* extent = new Extent('EPSG:4326', 12, 14, 35, 46);
* layer.projection = 'EPSG:4326';
* layer.url = 'http://server.geo/wms/BBOX=%bbox&FORMAT=jpg&SERVICE=WMS';
* url = URLBuilder.bbox(extent, layer);
* source.projection = 'EPSG:4326';
* source.url = 'http://server.geo/wms/BBOX=%bbox&FORMAT=jpg&SERVICE=WMS';
* url = URLBuilder.bbox(extent, source);
*
* // The resulting url is:
* // http://server.geo/wms/BBOX=12,35,14,46&FORMAT=jpg&SERVICE=WMS
*
* @param {Extent} bbox - the bounding box
* @param {Layer} layer
* @param {Source} source
*
* @return {string} the formed url
*/
bbox: function bbox(bbox, layer) {
const precision = layer.projection == 'EPSG:4326' ? 9 : 2;
bbox.as(layer.projection, extent);
bbox: function bbox(bbox, source) {
const precision = source.projection == 'EPSG:4326' ? 9 : 2;
bbox.as(source.projection, extent);
const w = extent.west.toFixed(precision);
const s = extent.south.toFixed(precision);
const e = extent.east.toFixed(precision);
const n = extent.north.toFixed(precision);

let bboxInUnit = layer.axisOrder || 'wsen';
let bboxInUnit = source.axisOrder || 'wsen';
bboxInUnit = bboxInUnit.replace('w', `${w},`)
.replace('s', `${s},`)
.replace('e', `${e},`)
.replace('n', `${n},`)
.slice(0, -1);

return layer.url.replace('%bbox', bboxInUnit);
return subDomains(source.url.replace('%bbox', bboxInUnit));
},
};
32 changes: 22 additions & 10 deletions test/unit/provider_url.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,42 +7,54 @@ const layer = {};

describe('URL creations', function () {
it('should correctly replace ${x}, ${y} and ${z} by 359, 512 and 10', function () {
var coords = new Extent('TMS', 10, 512, 359);
const coords = new Extent('TMS', 10, 512, 359);
layer.url = 'http://server.geo/tms/${z}/${y}/${x}.jpg';
var result = URLBuilder.xyz(coords, layer);
const result = URLBuilder.xyz(coords, layer);
assert.equal(result, 'http://server.geo/tms/10/512/359.jpg');
});

it('should correctly replace %COL, %ROW, %TILEMATRIX by 2072, 1410 and 12', function () {
var coords = new Extent('WMTS:WGS84', 12, 1410, 2072);
const coords = new Extent('WMTS:WGS84', 12, 1410, 2072);
layer.url = 'http://server.geo/wmts/SERVICE=WMTS&TILEMATRIX=%TILEMATRIX&TILEROW=%ROW&TILECOL=%COL';
var result = URLBuilder.xyz(coords, layer);
const result = URLBuilder.xyz(coords, layer);
assert.equal(result, 'http://server.geo/wmts/SERVICE=WMTS&TILEMATRIX=12&TILEROW=1410&TILECOL=2072');
});

it('should correctly replace %bbox by 12,35,14,46', function () {
var extent = new Extent('EPSG:4978', 12, 14, 35, 46);
const extent = new Extent('EPSG:4978', 12, 14, 35, 46);
layer.projection = 'EPSG:4978';
layer.url = 'http://server.geo/wms/BBOX=%bbox&FORMAT=jpg&SERVICE=WMS';
var result = URLBuilder.bbox(extent, layer);
const result = URLBuilder.bbox(extent, layer);
assert.equal(result, 'http://server.geo/wms/BBOX=12.00,35.00,14.00,46.00&FORMAT=jpg&SERVICE=WMS');
});

it('should correctly replace %bbox by 12,14,35,46', function () {
var extent = new Extent('EPSG:4326', 12, 14, 35, 46);
const extent = new Extent('EPSG:4326', 12, 14, 35, 46);
layer.projection = 'EPSG:4326';
layer.axisOrder = 'wesn';
layer.url = 'http://server.geo/wms/BBOX=%bbox&FORMAT=jpg&SERVICE=WMS';
var result = URLBuilder.bbox(extent, layer);
const result = URLBuilder.bbox(extent, layer);
assert.equal(result, 'http://server.geo/wms/BBOX=12.000000000,14.000000000,35.000000000,46.000000000&FORMAT=jpg&SERVICE=WMS');
});

it('shouldn\'t use the scientific notation', function () {
var extent = new Extent('EPSG:4326', 1 / 9999999999, 14, 35, 46);
const extent = new Extent('EPSG:4326', 1 / 9999999999, 14, 35, 46);
layer.projection = 'EPSG:4326';
layer.axisOrder = 'wesn';
layer.url = 'http://bla/wms/BBOX=%bbox&FORMAT=jpg&SERVICE=WMS';
var result = URLBuilder.bbox(extent, layer);
const result = URLBuilder.bbox(extent, layer);
assert.ok(result.indexOf('1e'), -1);
});

it('should correctly replace sub-domains pattern', function () {
layer.url = 'https://${u:xyz.org|yzx.org|zxy.org}/img.png';
assert.equal(URLBuilder.xyz({}, layer), 'https://xyz.org/img.png');
assert.equal(URLBuilder.xyz({}, layer), 'https://yzx.org/img.png');
assert.equal(URLBuilder.xyz({}, layer), 'https://zxy.org/img.png');

layer.url = 'https://${u:a|b|c}.tile.openstreetmap.org/img.png';
assert.equal(URLBuilder.xyz({}, layer), 'https://a.tile.openstreetmap.org/img.png');
assert.equal(URLBuilder.xyz({}, layer), 'https://b.tile.openstreetmap.org/img.png');
assert.equal(URLBuilder.xyz({}, layer), 'https://c.tile.openstreetmap.org/img.png');
});
});

0 comments on commit 5638615

Please sign in to comment.