var inherit = require('./inherit');
var tileLayer = require('./tileLayer');
var registry = require('./registry');
var quadFeature = require('./quadFeature');
var util = require('./util');
/**
* Object specification for an OSM layer.
*
* @typedef {geo.tileLayer.spec} geo.osmLayer.spec
* @extends {geo.tileLayer.spec}
* @property {number} [mapOpacity] If specified, and `opacity` is not
* specified, use this as the layer opacity.
* @property {string} [source] If specified, use the predefined tile source
* (see {@link geo.osmLayer.tileSources}).
* @property {string} [crossDomain='anonymous'] Image CORS attribute. This is
* used for the `crossorigin` property when loading images.
*/
/**
* Create a new instance of osmLayer. This is a {@link geo.tileLayer} with
* an OSM url and attribution defaults and with the tiles centered on the
* origin.
*
* @class
* @alias geo.osmLayer
* @extends geo.tileLayer
*
* @param {geo.osmLayer.spec} [arg] Specification for the layer.
*/
var osmLayer = function (arg) {
var imageTile = require('./imageTile');
if (!(this instanceof osmLayer)) {
return new osmLayer(arg);
}
arg = arg || {};
if (arg.mapOpacity !== undefined && arg.opacity === undefined) {
arg = Object.assign({}, arg);
arg.opacity = arg.mapOpacity;
}
arg = util.deepMerge(
{},
this.constructor.defaults,
osmLayer.tileSources[this.constructor.defaults.source] || {},
osmLayer.tileSources[arg.source] || {},
// don't name the layer based on the source
{name: ''},
arg);
tileLayer.call(this, arg);
var m_this = this;
/* mapOpacity is just another name for the layer opacity. */
this.mapOpacity = this.opacity;
/**
* Returns an instantiated imageTile object with the given indices. This
* method always returns a new tile object. Use `_getTileCached` to use
* the caching layer.
*
* @param {object} index The tile index.
* @param {number} index.x
* @param {number} index.y
* @param {number} index.level
* @param {object} source The tile index used for constructing the url.
* @param {number} source.x
* @param {number} source.y
* @param {number} source.level
* @returns {geo.tile}
*/
this._getTile = function (index, source) {
var urlParams = source || index;
return imageTile({
index: index,
size: {x: m_this._options.tileWidth, y: m_this._options.tileHeight},
queue: m_this._queue,
overlap: m_this._options.tileOverlap,
scale: m_this._options.tileScale,
url: m_this._options.url.call(
m_this, urlParams.x, urlParams.y, urlParams.level || 0,
m_this._options.subdomains),
crossDomain: m_this._options.crossDomain
});
};
/**
* Get or set a defined tile source. Tile sources are defined in
* {@link geo.osmLayer.tileSources}.
*
* @param {string} [source] The name of a defined tile source or `undefined`
* get the current named tile source, if any.
* @returns {string|undefined|this} Either the name of the current tile
* source, if any. Returns `this` when setting the source.
*/
this.source = function (source) {
if (source === undefined) {
for (const key in osmLayer.tileSources) {
if (osmLayer.tileSources[key].url === m_this.url()) {
return key;
}
}
return;
}
if (osmLayer.tileSources[source]) {
m_this.url(osmLayer.tileSources[source].url);
m_this.subdomains(osmLayer.tileSources[source].subdomains || 'abc');
m_this.attribution(osmLayer.tileSources[source].attribution || '');
m_this._options.maxLevel = osmLayer.tileSources[source].maxLevel || 18;
m_this._options.minLevel = osmLayer.tileSources[source].minLevel || 0;
}
return m_this;
};
};
/**
* This object contains the default options used to initialize the osmLayer.
*/
osmLayer.defaults = Object.assign({}, tileLayer.defaults, {
tileOffset : function (level) {
var s = Math.pow(2, level - 1) * 256;
return {x: s, y: s};
},
url: '',
source: 'osm'
});
/* Stamen's website (http://maps.stamen.com) as of 2019-08-28 says that the
* maps they host may be used free of charge. For http access, use a url like
* http://{s}.tile.stamen.com/toner-lite/{z}/{x}/{y}.png */
const StamenAttribution = 'Map tiles by <a href="http://stamen.com">Stamen ' +
'Design</a>, under <a href="http://creativecommons.org/licenses/by/3.0">' +
'CC BY 3.0</a>. Data by <a href="http://openstreetmap.org">OpenStreetMap' +
'</a>, under <a href="http://www.openstreetmap.org/copyright">ODbL</a>.';
/* Per Carto's website regarding basemap attribution: https://carto.com/help/working-with-data/attribution/#basemaps */
const CartoAttribution = '<a href="https://carto.com"> Carto</a> ' + 'Contributors <a href="https://www.openstreetmap.org/"> OpenStreetMap</a>';
/**
* This is a list of known tile sources. It can be added to via
* `geo.osmLayer.tilesource[<key>] = <object>`, where the object has `url`,
* `attribution`, `subdomains`, `minLevel`, and `maxLevel` defined.
*
* @type {object}
*/
osmLayer.tileSources = {
'dark-matter-with-labels': {
url: ' https://{s}.basemaps.cartocdn.com/rastertiles/dark_all/{z}/{x}/{y}.png',
attribution: CartoAttribution,
name: 'Carto Dark Matter With Labels',
minLevel: 0,
maxLevel: 18
},
'dark-matter-without-labels': {
url: 'https://{s}.basemaps.cartocdn.com/rastertiles/dark_nolabels/{z}/{x}/{y}.png',
attribution: CartoAttribution,
name: 'Carto Dark Matter Without Labels',
minLevel: 0,
maxLevel: 18
},
'nationalmap-relief': {
url: 'https://basemap.nationalmap.gov/arcgis/rest/services/USGSShadedReliefOnly/MapServer/tile/{z}/{y}/{x}',
attribution: 'Tile data from <a href="https://basemap.nationalmap.gov/">USGS</a>',
name:'National Map Shaded Relief',
minLevel: 0,
maxLevel: 16
},
'nationalmap-satellite': {
url: 'https://basemap.nationalmap.gov/arcgis/rest/services/USGSImageryOnly/MapServer/tile/{z}/{y}/{x}',
attribution: 'Tile data from <a href="https://basemap.nationalmap.gov/">USGS</a>',
name:'National Map Satellite',
minLevel: 0,
maxLevel: 16
},
'nationalmap-satellite-topo': {
url: 'https://basemap.nationalmap.gov/arcgis/rest/services/USGSImageryTopo/MapServer/tile/{z}/{y}/{x}',
attribution: 'Tile data from <a href="https://basemap.nationalmap.gov/">USGS</a>',
name:'National Map Satellite and Topo',
minLevel: 0,
maxLevel: 16
},
'nationalmap-topo': {
url: 'https://basemap.nationalmap.gov/arcgis/rest/services/USGSTopo/MapServer/tile/{z}/{y}/{x}',
attribution: 'Tile data from <a href="https://basemap.nationalmap.gov/">USGS</a>',
name:'National Map Topo',
minLevel: 0,
maxLevel: 16
},
osm: {
url: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
attribution: 'Tile data © <a href="https://osm.org/copyright">' +
'OpenStreetMap</a> contributors',
name:'OpenStreetMap',
subdomains: 'abc',
minLevel: 0,
maxLevel: 19
},
'positron-with-labels': {
url: 'https://{s}.basemaps.cartocdn.com/rastertiles/light_all/{z}/{x}/{y}.png',
attribution: CartoAttribution,
name:'Carto Positron With Labels',
minLevel: 0,
maxLevel: 18
},
'positron-without-labels': {
url: 'https://{s}.basemaps.cartocdn.com/rastertiles/light_nolabels/{z}/{x}/{y}.png',
attribution: CartoAttribution,
name:'Carto Positron Without Labels',
minLevel: 0,
maxLevel: 18
},
'stamen-terrain': {
url: 'https://stamen-tiles-{s}.a.ssl.fastly.net/terrain/{z}/{x}/{y}.png',
attribution: StamenAttribution,
name:'Stamen Terrain',
subdomains: 'abcd',
minLevel: 0,
maxLevel: 14
},
'stamen-terrain-background': {
url: 'https://stamen-tiles-{s}.a.ssl.fastly.net/terrain-background/{z}/{x}/{y}.png',
attribution: StamenAttribution,
name:'Stamen Terrain Background',
subdomains: 'abcd',
minLevel: 0,
maxLevel: 14
},
'stamen-toner': {
url: 'https://stamen-tiles-{s}.a.ssl.fastly.net/toner/{z}/{x}/{y}.png',
attribution: StamenAttribution,
name:'Stamen Toner',
subdomains: 'abcd',
minLevel: 0,
maxLevel: 20
},
'stamen-toner-lite': {
url: 'https://stamen-tiles-{s}.a.ssl.fastly.net/toner-lite/{z}/{x}/{y}.png',
attribution: StamenAttribution,
name:'Stamen Toner Lite',
subdomains: 'abcd',
minLevel: 0,
maxLevel: 20
},
'voyager-with-labels': {
url: 'https://{s}.basemaps.cartocdn.com/rastertiles/voyager_labels_under/{z}/{x}/{y}.png',
attribution: CartoAttribution,
name:'Carto Voyager With Labels',
minLevel: 0,
maxLevel: 18
},
'voyager-without-labels': {
url: 'https://{s}.basemaps.cartocdn.com/rastertiles/voyager_nolabels/{z}/{x}/{y}.png',
attribution: CartoAttribution,
name:'Carto Voyager Without Labels',
minLevel: 0,
maxLevel: 18
}
};
inherit(osmLayer, tileLayer);
/* By default, ask to support image quads. If the user needs full
* reprojection, they will need to require the
* quadFeature.capabilities.imageFull feature */
registry.registerLayer('osm', osmLayer, [quadFeature.capabilities.image]);
module.exports = osmLayer;