Make default layers customizable
This commit is contained in:
parent
e02be4ca15
commit
944ccd6cfa
6 changed files with 319 additions and 210 deletions
|
|
@ -43,6 +43,7 @@ var paths = {
|
||||||
'js/Browser.js',
|
'js/Browser.js',
|
||||||
'js/Util.js',
|
'js/Util.js',
|
||||||
'js/Map.js',
|
'js/Map.js',
|
||||||
|
'js/LayersConfig.js',
|
||||||
'js/router/BRouter.js',
|
'js/router/BRouter.js',
|
||||||
'js/plugin/*.js',
|
'js/plugin/*.js',
|
||||||
'js/control/*.js',
|
'js/control/*.js',
|
||||||
|
|
|
||||||
|
|
@ -286,6 +286,8 @@
|
||||||
<button type="button" id="expand_tree_button" class="btn btn-sm" data-i18n="[title]sidebar.layers.expand" title="Expand all"><span class="fa fa-plus-square-o"></span></button>
|
<button type="button" id="expand_tree_button" class="btn btn-sm" data-i18n="[title]sidebar.layers.expand" title="Expand all"><span class="fa fa-plus-square-o"></span></button>
|
||||||
<button type="button" id="collapse_tree_button" class="btn btn-sm" data-i18n="[title]sidebar.layers.collapse" title="Collapse all"><span class="fa fa-minus-square-o"></span></button>
|
<button type="button" id="collapse_tree_button" class="btn btn-sm" data-i18n="[title]sidebar.layers.collapse" title="Collapse all"><span class="fa fa-minus-square-o"></span></button>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- empty dummy to keep following buttons right-aligned when previous hidden -->
|
||||||
|
<div></div>
|
||||||
<div>
|
<div>
|
||||||
<button type="button" id="optional_layers_button" class="btn btn-sm" data-i18n="[title]sidebar.layers.optional" title="Add or remove optional layers"><span class="fa fa-cogs"></span> <span data-i18n="sidebar.layers.optional-layers">More</span></button>
|
<button type="button" id="optional_layers_button" class="btn btn-sm" data-i18n="[title]sidebar.layers.optional" title="Add or remove optional layers"><span class="fa fa-cogs"></span> <span data-i18n="sidebar.layers.optional-layers">More</span></button>
|
||||||
<button type="button" id="custom_layers_button" class="btn btn-sm" data-i18n="[title]sidebar.layers.customize" title="Add or remove custom layers"><span class="fa fa-plus-square"></span> <span data-i18n="sidebar.layers.custom-layers">Custom layers</span></button>
|
<button type="button" id="custom_layers_button" class="btn btn-sm" data-i18n="[title]sidebar.layers.customize" title="Add or remove custom layers"><span class="fa fa-plus-square"></span> <span data-i18n="sidebar.layers.custom-layers">Custom layers</span></button>
|
||||||
|
|
|
||||||
239
js/LayersConfig.js
Normal file
239
js/LayersConfig.js
Normal file
|
|
@ -0,0 +1,239 @@
|
||||||
|
BR.LayersConfig = L.Class.extend({
|
||||||
|
defaultBaseLayers: [
|
||||||
|
'standard',
|
||||||
|
'osm-mapnik-german_style',
|
||||||
|
'OpenTopoMap',
|
||||||
|
'Stamen.Terrain',
|
||||||
|
'Esri.WorldImagery'
|
||||||
|
],
|
||||||
|
defaultOverlays: [
|
||||||
|
'HikeBike.HillShading',
|
||||||
|
'Waymarked_Trails-Cycling',
|
||||||
|
'Waymarked_Trails-Hiking'
|
||||||
|
],
|
||||||
|
|
||||||
|
initialize: function (map) {
|
||||||
|
this._map = map;
|
||||||
|
|
||||||
|
this._addLeafletProvidersLayers();
|
||||||
|
|
||||||
|
this._customizeLayers();
|
||||||
|
},
|
||||||
|
|
||||||
|
_addLeafletProvidersLayers: function () {
|
||||||
|
var includeList = [
|
||||||
|
'Stamen.Terrain',
|
||||||
|
'MtbMap',
|
||||||
|
'OpenStreetMap.CH',
|
||||||
|
'HikeBike.HillShading',
|
||||||
|
'Esri.WorldImagery'
|
||||||
|
];
|
||||||
|
|
||||||
|
for (var i = 0; i < includeList.length; i++) {
|
||||||
|
var id = includeList[i];
|
||||||
|
var obj = {
|
||||||
|
geometry: null,
|
||||||
|
properties: {
|
||||||
|
id: id,
|
||||||
|
name: id.replace('.', ' '),
|
||||||
|
dataSource: 'leaflet-providers'
|
||||||
|
},
|
||||||
|
type: "Feature"
|
||||||
|
};
|
||||||
|
BR.layerIndex[id] = obj;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_customizeLayers: function () {
|
||||||
|
// add Thunderforest API key variable
|
||||||
|
BR.layerIndex['opencylemap'].properties.url = 'https://{switch:a,b,c}.tile.thunderforest.com/cycle/{zoom}/{x}/{y}.png?apikey={keys_thunderforest}';
|
||||||
|
BR.layerIndex['1061'].properties.url = 'http://{s}.tile.thunderforest.com/outdoors/{z}/{x}/{y}.png?apikey={keys_thunderforest}';
|
||||||
|
|
||||||
|
BR.layerIndex['HikeBike.HillShading'].properties.overlay = true;
|
||||||
|
|
||||||
|
|
||||||
|
function setProperty(layerId, key, value) {
|
||||||
|
var layer = BR.layerIndex[layerId];
|
||||||
|
if (layer) {
|
||||||
|
layer.properties[key] = value;
|
||||||
|
} else {
|
||||||
|
console.error('Layer not found: ' + layerId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function setMapUrl(layerId, url) {
|
||||||
|
setProperty(layerId, 'mapUrl', url);
|
||||||
|
}
|
||||||
|
function setName(layerId, url) {
|
||||||
|
setProperty(layerId, 'name', url);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Layer attribution here only as short link to original site,
|
||||||
|
// to keep current position use placeholders: {zoom}/{lat}/{lon}
|
||||||
|
// Copyright attribution in index.html #credits
|
||||||
|
setMapUrl('standard', '<a target="_blank" href="https://www.openstreetmap.org/#map={zoom}/{lat}/{lon}">OpenStreetMap</a>');
|
||||||
|
setMapUrl('osm-mapnik-german_style', '<a target="_blank" href="https://www.openstreetmap.de/karte.html?zoom={zoom}&lat={lat}&lon={lon}&layers=B000TF">OpenStreetMap.de</a>');
|
||||||
|
setMapUrl('OpenTopoMap', '<a target="_blank" href="https://opentopomap.org/#map={zoom}/{lat}/{lon}">OpenTopoMap</a>');
|
||||||
|
setMapUrl('Stamen.Terrain', '<a target="_blank" href="http://maps.stamen.com/#terrain/{zoom}/{lat}/{lon}">' + i18next.t('map.layer.stamen-terrain') + '</a>');
|
||||||
|
setMapUrl('opencylemap', '<a target="_blank" href="https://www.opencyclemap.org/?zoom={zoom}&lat={lat}&lon={lon}&layers=B0000">OpenCycleMap</a>');
|
||||||
|
setMapUrl('1061', '<a target="_blank" href="https://www.opencyclemap.org/?zoom={zoom}&lat={lat}&lon={lon}&layers=000B0">Outdoors</a>');
|
||||||
|
setMapUrl('Esri.WorldImagery', '<a target="_blank" href="http://www.arcgis.com/home/item.html?id=10df2279f9684e4a9f6a7f08febac2a9">' + i18next.t('credits.esri-tiles') + '</a>');
|
||||||
|
setMapUrl('HikeBike.HillShading', '<a target="_blank" href="http://hikebikemap.org/?zoom={zoom}&lat={lat}&lon={lon}&layer=HikeBikeMap">' + i18next.t('map.hikebike-hillshading') + '</a>');
|
||||||
|
setMapUrl('Waymarked_Trails-Cycling', '<a target="_blank" href="http://cycling.waymarkedtrails.org/#?map={zoom}!{lat}!{lon}">' + i18next.t('map.cycling') + '</a>');
|
||||||
|
setMapUrl('Waymarked_Trails-Hiking', '<a target="_blank" href="http://hiking.waymarkedtrails.org/#?map={zoom}!{lat}!{lon}">' + i18next.t('map.hiking') + '</a>');
|
||||||
|
|
||||||
|
setName('standard', i18next.t('map.layer.osm'));
|
||||||
|
setName('osm-mapnik-german_style', i18next.t('map.layer.osmde'));
|
||||||
|
setName('OpenTopoMap', i18next.t('map.layer.topo'));
|
||||||
|
setName('Stamen.Terrain', i18next.t('map.layer.stamen-terrain'));
|
||||||
|
setName('opencylemap', i18next.t('map.layer.cycle'));
|
||||||
|
setName('1061', i18next.t('map.layer.outdoors'));
|
||||||
|
setName('Esri.WorldImagery', i18next.t('map.layer.esri'));
|
||||||
|
setName('HikeBike.HillShading', i18next.t('map.layer.hikebike-hillshading'));
|
||||||
|
setName('Waymarked_Trails-Cycling', i18next.t('map.layer.cycling'));
|
||||||
|
setName('Waymarked_Trails-Hiking', i18next.t('map.layer.hiking'));
|
||||||
|
},
|
||||||
|
|
||||||
|
isDefaultLayer: function(id, overlay) {
|
||||||
|
var result = false;
|
||||||
|
if (overlay) {
|
||||||
|
result = this.defaultOverlays.indexOf(id) > -1;
|
||||||
|
} else {
|
||||||
|
result = this.defaultBaseLayers.indexOf(id) > -1;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
|
||||||
|
getBaseLayers: function() {
|
||||||
|
return this._getLayers(this.defaultBaseLayers);
|
||||||
|
},
|
||||||
|
|
||||||
|
getOverlays: function() {
|
||||||
|
return this._getLayers(this.defaultOverlays);
|
||||||
|
},
|
||||||
|
|
||||||
|
_getLayers: function(ids) {
|
||||||
|
var layers = {};
|
||||||
|
|
||||||
|
for (var i = 0; i < ids.length; i++) {
|
||||||
|
var layerId = ids[i];
|
||||||
|
var layerData = BR.layerIndex[layerId];
|
||||||
|
|
||||||
|
if (layerData) {
|
||||||
|
layers[layerData.properties.name] = this.createLayer(layerData);
|
||||||
|
} else {
|
||||||
|
console.error('Layer not found: ' + layerId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return layers;
|
||||||
|
},
|
||||||
|
|
||||||
|
// own convention: key placeholder with prefix
|
||||||
|
// e.g. ?api_key={keys_openrouteservice}
|
||||||
|
getKeyName: function (url) {
|
||||||
|
var result = null;
|
||||||
|
// L.Util.template only matches [\w_-]
|
||||||
|
var prefix = 'keys_';
|
||||||
|
var regex = new RegExp('{' + prefix + '([^}]*)}');
|
||||||
|
var found, name;
|
||||||
|
|
||||||
|
if (!url) return result;
|
||||||
|
|
||||||
|
found = url.match(regex);
|
||||||
|
if (found) {
|
||||||
|
name = found[1];
|
||||||
|
result = {
|
||||||
|
name: name,
|
||||||
|
urlVar: prefix + name
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
|
||||||
|
createLayer: function (layerData) {
|
||||||
|
var props = layerData.properties;
|
||||||
|
var url = props.url;
|
||||||
|
var layer;
|
||||||
|
|
||||||
|
// JOSM: https://{switch:a,b,c}.tile.openstreetmap.org/{zoom}/{x}/{y}.png
|
||||||
|
// Leaflet: https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png
|
||||||
|
function convertUrlJosm(url) {
|
||||||
|
var rxSwitch = /{switch:[^}]*}/;
|
||||||
|
var rxZoom = /{zoom}/g;
|
||||||
|
var result = url.replace(rxSwitch, '{s}');
|
||||||
|
result = result.replace(rxZoom, '{z}');
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// JOSM: https://{switch:a,b,c}.tile.openstreetmap.org/{zoom}/{x}/{y}.png
|
||||||
|
// Leaflet: ['a','b','c']
|
||||||
|
function getSubdomains(url) {
|
||||||
|
var result = 'abc';
|
||||||
|
var regex = /{switch:([^}]*)}/;
|
||||||
|
var found = url.match(regex);
|
||||||
|
if (found) {
|
||||||
|
result = found[1].split(',');
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var options = {
|
||||||
|
maxZoom: this._map.getMaxZoom(),
|
||||||
|
mapUrl: props.mapUrl
|
||||||
|
};
|
||||||
|
|
||||||
|
var keyObj = this.getKeyName(url);
|
||||||
|
if (keyObj && BR.keys[keyObj.name]) {
|
||||||
|
options[keyObj.urlVar] = BR.keys[keyObj.name];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (props.dataSource === 'leaflet-providers') {
|
||||||
|
layer = L.tileLayer.provider(props.id);
|
||||||
|
|
||||||
|
var layerOptions = L.Util.extend(options, {
|
||||||
|
maxNativeZoom: layer.options.maxZoom,
|
||||||
|
});
|
||||||
|
L.setOptions(layer, layerOptions);
|
||||||
|
|
||||||
|
} else if (props.dataSource === 'LayersCollection') {
|
||||||
|
layer = L.tileLayer(url, L.Util.extend(options, {
|
||||||
|
minZoom: props.minZoom,
|
||||||
|
maxNativeZoom: props.maxZoom,
|
||||||
|
}));
|
||||||
|
if (props.subdomains) {
|
||||||
|
layer.subdomains = props.subdomains;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// JOSM
|
||||||
|
var url = convertUrlJosm(url);
|
||||||
|
|
||||||
|
var josmOptions = L.Util.extend(options, {
|
||||||
|
minZoom: props.min_zoom,
|
||||||
|
maxNativeZoom: props.max_zoom,
|
||||||
|
subdomains: getSubdomains(url),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (props.type && props.type === 'wms') {
|
||||||
|
layer = L.tileLayer.wms(url, L.Util.extend(josmOptions, {
|
||||||
|
layers: props.layers,
|
||||||
|
format: props.format
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
layer = L.tileLayer(url, josmOptions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var getAttribution = function () {
|
||||||
|
return this.options.mapUrl;
|
||||||
|
}
|
||||||
|
layer.getAttribution = getAttribution;
|
||||||
|
|
||||||
|
return layer;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
BR.layersConfig = function (map) {
|
||||||
|
return new BR.LayersConfig(map);
|
||||||
|
};
|
||||||
68
js/Map.js
68
js/Map.js
|
|
@ -8,59 +8,6 @@ BR.Map = {
|
||||||
|
|
||||||
var maxZoom = 19;
|
var maxZoom = 19;
|
||||||
|
|
||||||
// Layer attribution here only as short link to original site,
|
|
||||||
// to keep current position use placeholders: {zoom}/{lat}/{lon}
|
|
||||||
// Copyright attribution in index.html #credits
|
|
||||||
|
|
||||||
var osm = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
|
||||||
maxZoom: maxZoom,
|
|
||||||
attribution: '<a target="_blank" href="https://www.openstreetmap.org/#map={zoom}/{lat}/{lon}">OpenStreetMap</a>'
|
|
||||||
});
|
|
||||||
|
|
||||||
var osmde = L.tileLayer('https://{s}.tile.openstreetmap.de/tiles/osmde/{z}/{x}/{y}.png', {
|
|
||||||
maxNativeZoom: 19,
|
|
||||||
maxZoom: maxZoom,
|
|
||||||
attribution: '<a target="_blank" href="https://www.openstreetmap.de/karte.html?zoom={zoom}&lat={lat}&lon={lon}&layers=B000TF">OpenStreetMap.de</a>'
|
|
||||||
});
|
|
||||||
|
|
||||||
var topo = L.tileLayer('https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png', {
|
|
||||||
maxNativeZoom: 17,
|
|
||||||
maxZoom: maxZoom,
|
|
||||||
attribution: '<a target="_blank" href="https://opentopomap.org/#map={zoom}/{lat}/{lon}">OpenTopoMap</a>'
|
|
||||||
});
|
|
||||||
|
|
||||||
var thunderforestAuth = BR.keys.thunderforest ? '?apikey=' + BR.keys.thunderforest : '';
|
|
||||||
var cycle = L.tileLayer('https://{s}.tile.thunderforest.com/cycle/{z}/{x}/{y}.png' + thunderforestAuth, {
|
|
||||||
maxNativeZoom: 18,
|
|
||||||
maxZoom: maxZoom,
|
|
||||||
attribution: '<a target="_blank" href="https://www.opencyclemap.org/?zoom={zoom}&lat={lat}&lon={lon}&layers=B0000">OpenCycleMap</a>'
|
|
||||||
});
|
|
||||||
var outdoors = L.tileLayer('https://{s}.tile.thunderforest.com/outdoors/{z}/{x}/{y}.png' + thunderforestAuth, {
|
|
||||||
maxNativeZoom: 18,
|
|
||||||
maxZoom: maxZoom,
|
|
||||||
attribution: '<a target="_blank" href="https://www.opencyclemap.org/?zoom={zoom}&lat={lat}&lon={lon}&layers=000B0">Outdoors</a>'
|
|
||||||
});
|
|
||||||
|
|
||||||
var esri = L.tileLayer('https://{s}.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', {
|
|
||||||
maxNativeZoom: 19,
|
|
||||||
maxZoom: maxZoom,
|
|
||||||
subdomains: ['server', 'services'],
|
|
||||||
attribution: '<a target="_blank" href="http://www.arcgis.com/home/item.html?id=10df2279f9684e4a9f6a7f08febac2a9">' + i18next.t('credits.esri-tiles') + '</a>'
|
|
||||||
});
|
|
||||||
|
|
||||||
var cycling = L.tileLayer('https://tile.waymarkedtrails.org/cycling/{z}/{x}/{y}.png', {
|
|
||||||
maxNativeZoom: 18,
|
|
||||||
opacity: 0.7,
|
|
||||||
maxZoom: maxZoom,
|
|
||||||
attribution: '<a target="_blank" href="http://cycling.waymarkedtrails.org/#?map={zoom}!{lat}!{lon}">' + i18next.t('map.cycling') + '</a>'
|
|
||||||
});
|
|
||||||
var hiking = L.tileLayer('https://tile.waymarkedtrails.org/hiking/{z}/{x}/{y}.png', {
|
|
||||||
maxNativeZoom: 18,
|
|
||||||
opacity: 0.7,
|
|
||||||
maxZoom: maxZoom,
|
|
||||||
attribution: '<a target="_blank" href="http://hiking.waymarkedtrails.org/#?map={zoom}!{lat}!{lon}">' + i18next.t('map.hiking') + '</a>'
|
|
||||||
});
|
|
||||||
|
|
||||||
map = new L.Map('map', {
|
map = new L.Map('map', {
|
||||||
zoomControl: false, // add it manually so that we can translate it
|
zoomControl: false, // add it manually so that we can translate it
|
||||||
worldCopyJump: true,
|
worldCopyJump: true,
|
||||||
|
|
@ -85,16 +32,9 @@ BR.Map = {
|
||||||
new L.Control.PermalinkAttribution().addTo(map);
|
new L.Control.PermalinkAttribution().addTo(map);
|
||||||
map.attributionControl.setPrefix(false);
|
map.attributionControl.setPrefix(false);
|
||||||
|
|
||||||
var baseLayers = {}
|
var layersConfig = BR.layersConfig(map);
|
||||||
baseLayers[i18next.t('map.layer.osm')] = osm;
|
var baseLayers = layersConfig.getBaseLayers();
|
||||||
baseLayers[i18next.t('map.layer.osmde')] = osmde;
|
var overlays = layersConfig.getOverlays();
|
||||||
baseLayers[i18next.t('map.layer.topo')] = topo;
|
|
||||||
baseLayers[i18next.t('map.layer.cycle')] = cycle;
|
|
||||||
baseLayers[i18next.t('map.layer.outdoors')] = outdoors;
|
|
||||||
baseLayers[i18next.t('map.layer.esri')] = esri;
|
|
||||||
var overlays = {}
|
|
||||||
overlays[i18next.t('map.layer.cycling')] = cycling;
|
|
||||||
overlays[i18next.t('map.layer.hiking')] = hiking;
|
|
||||||
|
|
||||||
if (BR.keys.bing) {
|
if (BR.keys.bing) {
|
||||||
baseLayers[i18next.t('map.layer.bing')] = new BR.BingLayer(BR.keys.bing);
|
baseLayers[i18next.t('map.layer.bing')] = new BR.BingLayer(BR.keys.bing);
|
||||||
|
|
@ -129,7 +69,7 @@ BR.Map = {
|
||||||
map.addLayer(defaultLayer);
|
map.addLayer(defaultLayer);
|
||||||
}
|
}
|
||||||
|
|
||||||
layersControl = BR.layersTab(baseLayers, overlays).addTo(map);
|
layersControl = BR.layersTab(layersConfig, baseLayers, overlays).addTo(map);
|
||||||
|
|
||||||
var secureContext = 'isSecureContext' in window ? isSecureContext : location.protocol === 'https:';
|
var secureContext = 'isSecureContext' in window ? isSecureContext : location.protocol === 'https:';
|
||||||
if (secureContext) {
|
if (secureContext) {
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,12 @@ BR.LayersTab = L.Control.Layers.extend({
|
||||||
previewLayer: null,
|
previewLayer: null,
|
||||||
saveLayers: [],
|
saveLayers: [],
|
||||||
|
|
||||||
|
initialize: function (layersConfig, baseLayers, overlays, options) {
|
||||||
|
L.Control.Layers.prototype.initialize.call(this, baseLayers, overlays, options);
|
||||||
|
|
||||||
|
this.layersConfig = layersConfig;
|
||||||
|
},
|
||||||
|
|
||||||
addTo: function (map) {
|
addTo: function (map) {
|
||||||
this._map = map;
|
this._map = map;
|
||||||
this.onAdd(map);
|
this.onAdd(map);
|
||||||
|
|
@ -12,33 +18,32 @@ BR.LayersTab = L.Control.Layers.extend({
|
||||||
|
|
||||||
this.initButtons();
|
this.initButtons();
|
||||||
|
|
||||||
this.addLeafletProvidersLayers();
|
|
||||||
|
|
||||||
var structure = {
|
var structure = {
|
||||||
'Base layers': {
|
'Base layers': {
|
||||||
'Worldwide international': [
|
'Worldwide international': [
|
||||||
'standard',
|
'standard',
|
||||||
'OpenTopoMap',
|
'OpenTopoMap',
|
||||||
'Stamen.Terrain',
|
'Stamen.Terrain',
|
||||||
'HDM_HOT',
|
'Esri.WorldImagery',
|
||||||
'wikimedia-map',
|
'wikimedia-map',
|
||||||
|
'HDM_HOT',
|
||||||
|
'1010', // OpenStreetMap.se (Hydda.Full)
|
||||||
'opencylemap',
|
'opencylemap',
|
||||||
"1061", // Thunderforest Outdoors
|
'1061', // Thunderforest Outdoors
|
||||||
"1065", // Hike & Bike Map
|
'1065', // Hike & Bike Map
|
||||||
"1016", // 4UMaps,
|
'1016', // 4UMaps,
|
||||||
"openmapsurfer"
|
'openmapsurfer'
|
||||||
],
|
],
|
||||||
'Worldwide monolingual': [
|
'Worldwide monolingual': [
|
||||||
'osm-mapnik-german_style',
|
'osm-mapnik-german_style',
|
||||||
'osmfr',
|
'osmfr',
|
||||||
"1023", // Osmapa.pl - Mapa OpenStreetMap Polska
|
'1023', // Osmapa.pl - Mapa OpenStreetMap Polska
|
||||||
"1021", // kosmosnimki.ru
|
'1021', // kosmosnimki.ru
|
||||||
"1017", // sputnik.ru
|
'1017' // sputnik.ru
|
||||||
"1010" // OpenStreetMap.se (Hydda.Full)
|
|
||||||
],
|
],
|
||||||
'Europe': [
|
'Europe': [
|
||||||
'MtbMap',
|
'MtbMap',
|
||||||
"1069", // MRI (maps.refuges.info)
|
'1069' // MRI (maps.refuges.info)
|
||||||
],
|
],
|
||||||
'Country': [
|
'Country': [
|
||||||
'topplus-open',
|
'topplus-open',
|
||||||
|
|
@ -76,7 +81,7 @@ BR.LayersTab = L.Control.Layers.extend({
|
||||||
'mapaszlakow-bike',
|
'mapaszlakow-bike',
|
||||||
'mapaszlakow-hike',
|
'mapaszlakow-hike',
|
||||||
'mapaszlakow-mtb',
|
'mapaszlakow-mtb',
|
||||||
'mapaszlakow-incline',
|
'mapaszlakow-incline'
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
@ -119,13 +124,14 @@ BR.LayersTab = L.Control.Layers.extend({
|
||||||
var obj = this._getLayerObjByName(data.node.text);
|
var obj = this._getLayerObjByName(data.node.text);
|
||||||
if (!obj) return;
|
if (!obj) return;
|
||||||
|
|
||||||
|
this.removeLayer(obj.layer);
|
||||||
|
|
||||||
if (this._map.hasLayer(obj.layer)) {
|
if (this._map.hasLayer(obj.layer)) {
|
||||||
this._map.removeLayer(obj.layer);
|
this._map.removeLayer(obj.layer);
|
||||||
if (!obj.overlay) {
|
if (!obj.overlay) {
|
||||||
this.addFirstLayer();
|
this.addFirstLayer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.removeLayer(obj.layer);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
$('#optional-layers-tree')
|
$('#optional-layers-tree')
|
||||||
|
|
@ -188,10 +194,7 @@ BR.LayersTab = L.Control.Layers.extend({
|
||||||
var data = [];
|
var data = [];
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
function walkTree(inTree, outTree) {
|
function createRootNode(name) {
|
||||||
function walkObject(obj) {
|
|
||||||
for (name in obj) {
|
|
||||||
var value = obj[name];
|
|
||||||
var children = [];
|
var children = [];
|
||||||
var rootNode = {
|
var rootNode = {
|
||||||
'text': name,
|
'text': name,
|
||||||
|
|
@ -200,9 +203,36 @@ BR.LayersTab = L.Control.Layers.extend({
|
||||||
},
|
},
|
||||||
'children': children
|
'children': children
|
||||||
};
|
};
|
||||||
outTree.push(rootNode);
|
return rootNode;
|
||||||
|
}
|
||||||
|
|
||||||
walkTree(value, children);
|
function createNode(id, layerData) {
|
||||||
|
var props = layerData.properties;
|
||||||
|
var url = props.url;
|
||||||
|
var keyObj = self.layersConfig.getKeyName(url);
|
||||||
|
var childNode = null;
|
||||||
|
|
||||||
|
// when key required only add if configured
|
||||||
|
if (!keyObj || keyObj && BR.keys[keyObj.name]) {
|
||||||
|
childNode = {
|
||||||
|
'id': id,
|
||||||
|
'text': props.name,
|
||||||
|
'state': {
|
||||||
|
'checked': self.layersConfig.isDefaultLayer(id, props.overlay)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return childNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
function walkTree(inTree, outTree) {
|
||||||
|
function walkObject(obj) {
|
||||||
|
for (name in obj) {
|
||||||
|
var value = obj[name];
|
||||||
|
var rootNode = createRootNode(name)
|
||||||
|
|
||||||
|
outTree.push(rootNode);
|
||||||
|
walkTree(value, rootNode.children);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -215,16 +245,8 @@ BR.LayersTab = L.Control.Layers.extend({
|
||||||
var layer = BR.layerIndex[entry];
|
var layer = BR.layerIndex[entry];
|
||||||
|
|
||||||
if (layer) {
|
if (layer) {
|
||||||
var props = layer.properties;
|
var childNode = createNode(entry, layer);
|
||||||
var url = props.url;
|
if (childNode) {
|
||||||
var keyName = self.getKeyName(url);
|
|
||||||
|
|
||||||
// when key required only add if configured
|
|
||||||
if (!keyName || keyName && BR.keys[keyName]) {
|
|
||||||
var childNode = {
|
|
||||||
'id': entry,
|
|
||||||
'text': props.name
|
|
||||||
};
|
|
||||||
outTree.push(childNode);
|
outTree.push(childNode);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -241,51 +263,13 @@ BR.LayersTab = L.Control.Layers.extend({
|
||||||
return data;
|
return data;
|
||||||
},
|
},
|
||||||
|
|
||||||
addLeafletProvidersLayers: function () {
|
addFirstLayer: function () {
|
||||||
var includeList = [
|
for (var i = 0; i < this._layers.length; i++) {
|
||||||
'Stamen.Terrain',
|
var obj = this._layers[i];
|
||||||
'MtbMap',
|
if (!obj.overlay) {
|
||||||
'OpenStreetMap.CH',
|
this._map.addLayer(obj.layer);
|
||||||
'HikeBike.HillShading'
|
break;
|
||||||
];
|
|
||||||
|
|
||||||
for (var i = 0; i < includeList.length; i++) {
|
|
||||||
var id = includeList[i];
|
|
||||||
var obj = {
|
|
||||||
geometry: null,
|
|
||||||
properties: {
|
|
||||||
id: id,
|
|
||||||
name: id.replace('.', ' '),
|
|
||||||
dataSource: 'leaflet-providers'
|
|
||||||
},
|
|
||||||
type: "Feature"
|
|
||||||
};
|
|
||||||
BR.layerIndex[id] = obj;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BR.layerIndex['HikeBike.HillShading'].properties.overlay = true;
|
|
||||||
},
|
|
||||||
|
|
||||||
// own convention: key placeholder prefixed with 'key_'
|
|
||||||
// e.g. ?api_key={keys_openrouteservice}
|
|
||||||
getKeyName: function (url) {
|
|
||||||
var name = null;
|
|
||||||
var regex = /{keys_([^}]*)}/;
|
|
||||||
var found;
|
|
||||||
|
|
||||||
if (!url) return name;
|
|
||||||
|
|
||||||
found = url.match(regex);
|
|
||||||
if (found) {
|
|
||||||
name = found[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
return name;
|
|
||||||
},
|
|
||||||
|
|
||||||
addFirstLayer() {
|
|
||||||
if (this._layers.length > 0) {
|
|
||||||
this._map.addLayer(this._layers[0].layer);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -298,73 +282,9 @@ BR.LayersTab = L.Control.Layers.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
createLayer: function (layerData) {
|
createLayer: function (layerData) {
|
||||||
var props = layerData.properties;
|
var layer = this.layersConfig.createLayer(layerData);
|
||||||
var url = props.url;
|
layer.options.zIndex = this._lastZIndex + 1;
|
||||||
var layer;
|
return layer;
|
||||||
|
|
||||||
// JOSM: https://{switch:a,b,c}.tile.openstreetmap.org/{zoom}/{x}/{y}.png
|
|
||||||
// Leaflet: https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png
|
|
||||||
function convertUrlJosm(url) {
|
|
||||||
var rxSwitch = /{switch:[^}]*}/;
|
|
||||||
var rxZoom = /{zoom}/g;
|
|
||||||
var result = url.replace(rxSwitch, '{s}');
|
|
||||||
result = result.replace(rxZoom, '{z}');
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// JOSM: https://{switch:a,b,c}.tile.openstreetmap.org/{zoom}/{x}/{y}.png
|
|
||||||
// Leaflet: ['a','b','c']
|
|
||||||
function getSubdomains(url) {
|
|
||||||
var result = 'abc';
|
|
||||||
var regex = /{switch:([^}]*)}/;
|
|
||||||
var found = url.match(regex);
|
|
||||||
if (found) {
|
|
||||||
result = found[1].split(',');
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
var options = {
|
|
||||||
maxZoom: this._map.getMaxZoom(),
|
|
||||||
zIndex: this._lastZIndex + 1
|
|
||||||
};
|
|
||||||
|
|
||||||
var keyName = this.getKeyName(url);
|
|
||||||
if (keyName && BR.keys[keyName]) {
|
|
||||||
options['keys_' + keyName] = BR.keys[keyName];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (props.dataSource === 'leaflet-providers') {
|
|
||||||
layer = L.tileLayer.provider(props.id);
|
|
||||||
} else if (props.dataSource === 'LayersCollection') {
|
|
||||||
layer = L.tileLayer(url, L.Util.extend(options, {
|
|
||||||
minZoom: props.minZoom,
|
|
||||||
maxNativeZoom: props.maxZoom,
|
|
||||||
}));
|
|
||||||
if (props.subdomains) {
|
|
||||||
layer.subdomains = props.subdomains;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// JOSM
|
|
||||||
var url = convertUrlJosm(url);
|
|
||||||
|
|
||||||
var josmOptions = L.Util.extend(options, {
|
|
||||||
minZoom: props.min_zoom,
|
|
||||||
maxNativeZoom: props.max_zoom,
|
|
||||||
subdomains: getSubdomains(url),
|
|
||||||
});
|
|
||||||
|
|
||||||
if (props.type && props.type === 'wms') {
|
|
||||||
layer = L.tileLayer.wms(url, L.Util.extend(josmOptions, {
|
|
||||||
layers: props.layers,
|
|
||||||
format: props.format
|
|
||||||
}));
|
|
||||||
} else {
|
|
||||||
layer = L.tileLayer(url, josmOptions);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return layer
|
|
||||||
},
|
},
|
||||||
|
|
||||||
removeSelectedLayers: function () {
|
removeSelectedLayers: function () {
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,7 @@
|
||||||
"delete-route": "Delete route?",
|
"delete-route": "Delete route?",
|
||||||
"draw-route-start": "Draw route (D key)",
|
"draw-route-start": "Draw route (D key)",
|
||||||
"draw-route-stop": "Stop drawing route (ESC key)",
|
"draw-route-stop": "Stop drawing route (ESC key)",
|
||||||
|
"hikebike-hillshading": "Hillshading",
|
||||||
"hiking": "Hiking",
|
"hiking": "Hiking",
|
||||||
"layer": {
|
"layer": {
|
||||||
"bing": "Bing Aerial",
|
"bing": "Bing Aerial",
|
||||||
|
|
@ -81,10 +82,12 @@
|
||||||
"cycling": "Cycling (Waymarked Trails)",
|
"cycling": "Cycling (Waymarked Trails)",
|
||||||
"digitalglobe": "DigitalGlobe Recent Imagery",
|
"digitalglobe": "DigitalGlobe Recent Imagery",
|
||||||
"esri": "Esri World Imagery",
|
"esri": "Esri World Imagery",
|
||||||
|
"hikebike-hillshading": "Hillshading (Hike & Bike Map)",
|
||||||
"hiking": "Hiking (Waymarked Trails)",
|
"hiking": "Hiking (Waymarked Trails)",
|
||||||
"osm": "OpenStreetMap",
|
"osm": "OpenStreetMap",
|
||||||
"osmde": "OpenStreetMap.de",
|
"osmde": "OpenStreetMap.de",
|
||||||
"outdoors": "Outdoors (Thunderforest)",
|
"outdoors": "Outdoors (Thunderforest)",
|
||||||
|
"stamen-terrain": "Terrain (Stamen)",
|
||||||
"strava-segments": "Strava segments",
|
"strava-segments": "Strava segments",
|
||||||
"topo": "OpenTopoMap"
|
"topo": "OpenTopoMap"
|
||||||
},
|
},
|
||||||
|
|
@ -157,8 +160,12 @@
|
||||||
"title": "Itinerary"
|
"title": "Itinerary"
|
||||||
},
|
},
|
||||||
"layers": {
|
"layers": {
|
||||||
|
"collapse": "Collapse all",
|
||||||
"custom-layers": "Custom layers",
|
"custom-layers": "Custom layers",
|
||||||
"customize": "Add or remove custom layers",
|
"customize": "Add or remove custom layers",
|
||||||
|
"expand": "Expand all",
|
||||||
|
"optional": "Add or remove optional layers",
|
||||||
|
"optional-layers": "More",
|
||||||
"table": {
|
"table": {
|
||||||
"URL": "URL",
|
"URL": "URL",
|
||||||
"empty": "No custom layer configured yet.",
|
"empty": "No custom layer configured yet.",
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue