Merge branch 'master' into feature/profile-sidebar

This commit is contained in:
Norbert Renner 2017-05-20 21:18:32 +02:00 committed by GitHub
commit 68538378fe
21 changed files with 707 additions and 231 deletions

View file

@ -8,28 +8,28 @@ BR.Map = {
var maxZoom = 19;
var osm = L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
var osm = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: maxZoom
});
var osmde = L.tileLayer('http://{s}.tile.openstreetmap.de/tiles/osmde/{z}/{x}/{y}.png', {
var osmde = L.tileLayer('https://{s}.tile.openstreetmap.de/tiles/osmde/{z}/{x}/{y}.png', {
maxNativeZoom: 18,
maxZoom: maxZoom
});
var topo = L.tileLayer('http://{s}.tile.opentopomap.org/{z}/{x}/{y}.png', {
var topo = L.tileLayer('https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png', {
maxNativeZoom: 17,
maxZoom: maxZoom
});
var thunderforestAttribution = 'tiles &copy; <a target="_blank" href="http://www.thunderforest.com">Thunderforest</a> '
+ '(<a target="_blank" href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA 2.0</a>)';
var thunderforestAttribution = 'tiles &copy; <a target="_blank" href="https://www.thunderforest.com">Thunderforest</a> '
+ '(<a target="_blank" href="https://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA 2.0</a>)';
var thunderforestAuth = BR.keys.thunderforest ? '?apikey=' + BR.keys.thunderforest : '';
var cycle = L.tileLayer('http://{s}.tile.thunderforest.com/cycle/{z}/{x}/{y}.png' + thunderforestAuth, {
var cycle = L.tileLayer('https://{s}.tile.thunderforest.com/cycle/{z}/{x}/{y}.png' + thunderforestAuth, {
maxNativeZoom: 18,
maxZoom: maxZoom
});
var outdoors = L.tileLayer('http://{s}.tile.thunderforest.com/outdoors/{z}/{x}/{y}.png' + thunderforestAuth, {
var outdoors = L.tileLayer('https://{s}.tile.thunderforest.com/outdoors/{z}/{x}/{y}.png' + thunderforestAuth, {
maxNativeZoom: 18,
maxZoom: maxZoom
});
@ -39,16 +39,16 @@ BR.Map = {
maxZoom: maxZoom,
subdomains: ['server', 'services'],
attribution: '<a target="_blank" href="http://goto.arcgisonline.com/maps/World_Imagery">World Imagery</a> '
+ '&copy; <a target="_blank" href="http://www.esri.com/">Esri</a>, sources: '
+ '&copy; <a target="_blank" href="https://www.esri.com/">Esri</a>, sources: '
+ 'Esri, DigitalGlobe, Earthstar Geographics, CNES/Airbus DS, GeoEye, USDA FSA, USGS, Getmapping, Aerogrid, IGN, IGP, and the GIS User Community'
});
});
var cycling = L.tileLayer('http://tile.waymarkedtrails.org/cycling/{z}/{x}/{y}.png', {
var cycling = L.tileLayer('https://tile.waymarkedtrails.org/cycling/{z}/{x}/{y}.png', {
maxNativeZoom: 18,
opacity: 0.7,
maxZoom: maxZoom
});
var hiking = L.tileLayer('http://tile.waymarkedtrails.org/hiking/{z}/{x}/{y}.png', {
var hiking = L.tileLayer('https://tile.waymarkedtrails.org/hiking/{z}/{x}/{y}.png', {
maxNativeZoom: 18,
opacity: 0.7,
maxZoom: maxZoom
@ -86,7 +86,7 @@ BR.Map = {
minZoom: 1,
maxZoom: 19,
attribution: '&copy; <a href="https://www.digitalglobe.com/platforms/mapsapi">DigitalGlobe</a> ('
+ '<a href="http://bit.ly/mapsapiview">Terms of Use</a>)'
+ '<a href="https://bit.ly/mapsapiview">Terms of Use</a>)'
});
baseLayers['DigitalGlobe Recent Imagery'] = recent;
}
@ -120,13 +120,20 @@ BR.Map = {
L.control.scale().addTo(map);
new BR.Layers().init(map, layersControl, baseLayers, overlays);
// expose map instance for console debugging
BR.debug = BR.debug || {};
BR.debug.map = map;
var layersAndOverlays = baseLayers;
for (var o in overlays) {
layersAndOverlays[o] = overlays[o];
}
return {
map: map,
layersControl: layersControl
layersControl: layersControl,
layers: layersAndOverlays
};
}

View file

@ -33,12 +33,12 @@ BR.Util = {
// check if localStorage is available, especially for catching SecurityError
// when cookie settings are blocking access (Chrome, Pale Moon, older Firefox)
//
//
// see also https://github.com/Modernizr/Modernizr/blob/master/feature-detects/storage/localstorage.js
//
//
// https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API#Testing_for_support_vs_availability
// by Mozilla Contributors, with modifications;
// Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/
// by Mozilla Contributors, with modifications;
// Any copyright is dedicated to the Public Domain. https://creativecommons.org/publicdomain/zero/1.0/
localStorageAvailable: function() {
try {
var storage = window.localStorage,

134
js/control/Layers.js Normal file
View file

@ -0,0 +1,134 @@
BR.Layers = L.Class.extend({
_loadLayers: function() {
this._customLayers = {};
if (BR.Util.localStorageAvailable()) {
var layers = JSON.parse(localStorage.getItem("map/customLayers"));
for (a in layers) {
this._addLayer(a, layers[a].layer, layers[a].isOverlay);
}
}
},
_loadTable: function() {
var layersData = [];
for (layer in this._customLayers) {
layersData.push([layer, this._customLayers[layer].layer._url, this._customLayers[layer].isOverlay ? "Overlay" : "Layer"]);
}
if (this._layersTable != null) {
this._layersTable.destroy();
}
this._layersTable = $('#custom_layers_table').DataTable({
data: layersData,
info: false,
searching: false,
paging: false,
columns: [
{ title: "Name" },
{ title: "URL" },
{ title: "Type" }
]
});
},
init: function(map, layersControl, baseLayers, overlays) {
this._layersControl = layersControl;
this._map = map;
this._layers = {}
for (var l in overlays)
this._layers[l] = [overlays[l], true];
for (var l in baseLayers)
this._layers[l] = [baseLayers[l], false];
L.DomUtil.get('custom_layers_add_base').onclick = L.bind(this._addBaseLayer, this);
L.DomUtil.get('custom_layers_add_overlay').onclick = L.bind(this._addOverlay, this);
L.DomUtil.get('custom_layers_remove').onclick = L.bind(this._remove, this);
this._loadLayers();
this._loadTable();
var table = this._layersTable;
$('#custom_layers_table tbody').on( 'click', 'tr', function () {
if ( $(this).hasClass('selected') ) {
$(this).removeClass('selected');
} else {
table.$('tr.selected').removeClass('selected');
$(this).addClass('selected');
}
});
addLayer = L.easyButton(
'fa-plus-square',
function () {
$('#custom_layers').modal();
},
'Add or remove custom layers',
{
position: 'topright'
}
).addTo(map);
},
_remove: function(evt) {
var row = this._layersTable.row('.selected').data();
if (row != null) {
var name = row[0];
this._layersControl.removeLayer(this._customLayers[name].layer);
this._map.removeLayer(this._customLayers[name].layer);
delete this._customLayers[name];
this._layersTable.row('.selected').remove().draw( false );
this._sync();
}
},
_addFromInput: function(isOverlay) {
var layer_name = L.DomUtil.get('layer_name').value;
var layer_url = L.DomUtil.get('layer_url').value;
if (layer_name.length > 0 && layer_url.length > 0)
this._addLayer(layer_name, layer_url, isOverlay);
},
_addBaseLayer: function(evt) {
this._addFromInput(false);
},
_addOverlay: function(evt) {
this._addFromInput(true);
},
_addLayer: function(layerName, layerUrl, isOverlay) {
if (layerName in this._layers)
return
if (layerName in this._customLayers)
return
try {
var layer = L.tileLayer(layerUrl);
this._customLayers[layerName] = {layer: layer, isOverlay: isOverlay};
if (isOverlay) {
this._layersControl.addOverlay(layer, layerName);
} else {
this._layersControl.addBaseLayer(layer, layerName);
}
this._loadTable();
this._sync();
return layer;
} catch (e) {
console.warn("Oops:", e);
return
}
},
_sync: function() {
if (BR.Util.localStorageAvailable()) {
localStorage.setItem("map/customLayers", JSON.stringify(this._customLayers, function(k, v) {
// dont write Leaflet.Layer in localStorage; simply keep the URL
return v._url || v;
}));
}
}
});

View file

@ -17,9 +17,10 @@ BR.RoutingOptions = BR.Control.extend({
return BR.Control.prototype.onAdd.call(this, map);
},
getOptions: function() {
refreshUI: function() {
var profile = $('#profile option:selected'),
alternative = $('#alternative option:selected');
$('#stat-profile').html(profile.text() + ' (' + alternative.text() +')');
// we do not allow to select more than one profile and/or alternative at a time
@ -36,8 +37,13 @@ BR.RoutingOptions = BR.Control.extend({
if (custom.value === "Custom") {
custom.disabled = true;
}
$('.selectpicker').selectpicker('refresh')
},
getOptions: function() {
var profile = $('#profile option:selected'),
alternative = $('#alternative option:selected');
this.refreshUI();
return {
profile: profile.val(),
@ -46,21 +52,19 @@ BR.RoutingOptions = BR.Control.extend({
},
setOptions: function(options) {
var profiles_grp,
profile = options.profile;
if (profile) {
profiles_grp = L.DomUtil.get('profile');
profiles_grp.value = profile;
var values = [
options.profile ? options.profile : $('#profile option:selected').val(),
options.alternative ? options.alternative : $('#alternative option:selected').val()
];
$('.selectpicker').selectpicker('val', values);
this.refreshUI();
if (options.profile) {
// profile got not selected = not in option values -> custom profile passed with permalink
if (profiles_grp.value != profile) {
this.setCustomProfile(profile, true);
if (L.DomUtil.get('profile').value != options.profile) {
this.setCustomProfile(options.profile, true);
}
}
if (options.alternative) {
L.DomUtil.get('alternative').value = options.alternative;
}
},
setCustomProfile: function(profile, noUpdate) {

View file

@ -11,6 +11,7 @@
function initApp(mapContext) {
var map = mapContext.map,
layersControl = mapContext.layersControl,
mapLayers = mapContext.layers,
search,
router,
routing,
@ -26,7 +27,7 @@
drawButton,
deleteButton,
drawToolbar,
permalink,
urlHash,
saveWarningShown = false;
// By default bootstrap-select use glyphicons
@ -70,7 +71,7 @@
if (result) {
routing.clear();
onUpdate();
permalink._update_routing();
urlHash.onMapMove();
}
}
});
@ -222,6 +223,7 @@
var sidebar = L.control.sidebar('sidebar', {
position: 'left'
});
sidebar.id = 'sidebar-control'; //required for persistence in local storage
map.addControl(sidebar);
nogos.addTo(map);
@ -229,29 +231,70 @@
callback: L.bind(routing.setOpacity, routing)
}));
// initial option settings (after controls are added and initialized with onAdd, before permalink)
// initial option settings (after controls are added and initialized with onAdd)
router.setOptions(nogos.getOptions());
router.setOptions(routingOptions.getOptions());
profile.update(routingOptions.getOptions());
permalink = new L.Control.Permalink({
text: 'Permalink',
position: 'bottomright',
layers: layersControl,
routingOptions: routingOptions,
nogos: nogos,
router: router,
routing: routing,
profile: profile
}).addTo(map);
var onHashChangeCb = function(url) {
var url2params = function (s) {
var p = {};
var sep = '&';
if (s.search('&amp;') !== -1)
sep = '&amp;';
var params = s.split(sep);
for (var i = 0; i < params.length; i++) {
var tmp = params[i].split('=');
if (tmp.length !== 2) continue;
p[tmp[0]] = decodeURIComponent(tmp[1]);
}
return p;
}
if (url == null) return;
var opts = router.parseUrlParams(url2params(url));
router.setOptions(opts);
routingOptions.setOptions(opts);
nogos.setOptions(opts);
profile.update(opts);
// FIXME permalink temporary hack
$('#permalink').on('click', function() {
$('#permalink-input').val($('.leaflet-control-permalink a')[0].href)
})
$('#permalink-input').on('click', function() {
$(this).select()
})
if (opts.lonlats) {
routing.draw(false);
routing.clear();
routing.setWaypoints(opts.lonlats);
}
};
var onInvalidHashChangeCb = function(params) {
params = params.replace('zoom=', 'map=');
params = params.replace('&lat=', '/');
params = params.replace('&lon=', '/');
params = params.replace('&layer=', '/');
return params;
};
// do not initialize immediately
urlHash = new L.Hash(null, null);
urlHash.additionalCb = function() {
var url = router.getUrl(routing.getWaypoints(), null).substr('brouter?'.length+1);
return url.length > 0 ? '&' + url : null;
};
urlHash.onHashChangeCb = onHashChangeCb;
urlHash.onInvalidHashChangeCb = onInvalidHashChangeCb;
urlHash.layers = mapLayers;
urlHash.map = map;
urlHash.init(map, mapLayers);
routingOptions.on('update', urlHash.onMapMove, urlHash);
nogos.on('update', urlHash.onMapMove, urlHash);
// waypoint add, move, delete (but last)
routing.on('routing:routeWaypointEnd', urlHash.onMapMove, urlHash);
// delete last waypoint
routing.on('waypoint:click', function (evt) {
var r = evt.marker._routing;
if (!r.prevMarker && !r.nextMarker) {
urlHash.onMapMove();
}
}, urlHash);
$(window).resize(function () {
elevation.addBelow(map);
@ -266,10 +309,34 @@
map._onResize();
});
$('#sidebar-btn').on('click', function (event) {
var onHide = function() {
if (this.id && BR.Util.localStorageAvailable()) {
localStorage[this.id] = 'true';
}
};
var onShow = function() {
if (this.id && BR.Util.localStorageAvailable()) {
localStorage.removeItem(this.id);
}
};
var toggleSidebar = function (event) {
sidebar.toggle();
$('#sidebar-btn').toggleClass('active');
});
};
$('#sidebar-btn').on('click', toggleSidebar);
sidebar.on('shown', onShow);
sidebar.on('hidden', onHide);
// on page load, we want to restore collapsible elements from previous usage
$('.collapse').on('hidden.bs.collapse', onHide)
.on('shown.bs.collapse', onShow)
.each(function() {
if (!(this.id && BR.Util.localStorageAvailable() && localStorage[this.id] === 'true' )) {
$(this).collapse('hide');
}
});
if (BR.Util.localStorageAvailable() && localStorage[sidebar.id] !== 'true') {
toggleSidebar();
}
}
mapContext = BR.Map.initMap();

View file

@ -1,8 +1,8 @@
BR.BingLayer = L.BingLayer.extend({
options: {
maxZoom: 19,
attribution: '<a target="_blank" href="http://www.bing.com/maps/">Bing Maps</a>'
+ ' (<a target="_blank" href="http://go.microsoft.com/?linkid=9710837">TOU</a>)'
attribution: '<a target="_blank" href="https://www.bing.com/maps/">Bing Maps</a>'
+ ' (<a target="_blank" href="https://go.microsoft.com/?linkid=9710837">TOU</a>)'
},
initialize: function(key, options) {
@ -11,7 +11,7 @@ BR.BingLayer = L.BingLayer.extend({
this._logo = L.control({position: 'bottomleft'});
this._logo.onAdd = function (map) {
this._div = L.DomUtil.create('div', 'bing-logo');
this._div.innerHTML = '<img src="http://www.microsoft.com/maps/images/branding/Bing%20logo%20white_50px-19px.png">';
this._div.innerHTML = '<img src="https://www.microsoft.com/maps/images/branding/Bing%20logo%20white_50px-19px.png">';
return this._div;
};
},

View file

@ -60,8 +60,8 @@ BR.NogoAreas = L.Control.Draw.extend({
setOptions: function(options) {
var nogos = options.nogos;
this.drawnItems.clearLayers();
if (nogos) {
this.drawnItems.clearLayers();
for (var i = 0; i < nogos.length; i++) {
this.drawnItems.addLayer(nogos[i]);
}

View file

@ -1,105 +0,0 @@
//#include "Permalink.js
// patch to not encode URL (beside 'layer', better readable/hackable, Browser can handle)
L.Control.Permalink.include({
_update_href: function () {
//var params = L.Util.getParamString(this._params);
var params = this.getParamString(this._params);
var sep = '?';
if (this.options.useAnchor) sep = '#';
var url = this._url_base + sep + params.slice(1);
if (this._href) this._href.setAttribute('href', url);
if (this.options.useLocation)
location.replace('#' + params.slice(1));
return url;
},
getParamString: function (obj, existingUrl, uppercase) {
var params = [];
for (var i in obj) {
// do encode layer (e.g. spaces)
if (i === 'layer') {
params.push(encodeURIComponent(uppercase ? i.toUpperCase() : i) + '=' + encodeURIComponent(obj[i]));
} else {
params.push(uppercase ? i.toUpperCase() : i + '=' + obj[i]);
}
}
return ((!existingUrl || existingUrl.indexOf('?') === -1) ? '?' : '&') + params.join('&');
}
});
// patch: no animation when setting the map view, strange effects with nogo circles
L.Control.Permalink.include({
_set_center: function(e)
{
//console.info('Update center', e);
var params = e.params;
if (params.zoom === undefined ||
params.lat === undefined ||
params.lon === undefined) return;
this._map.setView(new L.LatLng(params.lat, params.lon), params.zoom, { reset: true });
}
});
L.Control.Permalink.include({
initialize_routing: function () {
this.on('update', this._set_routing, this);
this.on('add', this._onadd_routing, this);
},
_onadd_routing: function (e) {
this.options.routingOptions.on('update', this._update_routing, this);
this.options.nogos.on('update', this._update_routing, this);
// waypoint add, move, delete (but last)
this.options.routing.on('routing:routeWaypointEnd', this._update_routing, this);
// delete last waypoint
this.options.routing.on('waypoint:click', function (evt) {
var r = evt.marker._routing;
if (!r.prevMarker && !r.nextMarker) {
this._update_routing(evt);
}
}, this);
},
_update_routing: function (evt) {
var router = this.options.router,
routing = this.options.routing,
routingOptions = this.options.routingOptions,
latLngs = routing.getWaypoints(),
params = router.getUrlParams(latLngs);
if (evt && evt.options) {
router.setOptions(evt.options);
}
// don't permalink to custom profile, as these are only stored temporarily
if (params.profile && params.profile === routingOptions.getCustomProfile()) {
params.profile = null;
}
this._update(params);
//console.log('permalink: ' + this._href.href);
},
_set_routing: function (e) {
var router = this.options.router,
routing = this.options.routing,
routingOptions = this.options.routingOptions,
nogos = this.options.nogos,
profile = this.options.profile;
var opts = router.parseUrlParams(e.params);
router.setOptions(opts);
routingOptions.setOptions(opts);
nogos.setOptions(opts);
profile.update(opts);
if (opts.lonlats) {
routing.draw(false);
routing.clear();
routing.setWaypoints(opts.lonlats);
}
}
});

View file

@ -152,7 +152,7 @@ BR.Routing = L.Routing.extend({
// transparent than with a single layer and the slider is non-linear. The
// inverted formula is used to get the same result as with a single layer.
// SVG simple alpha compositing: Ca' = 1 - (1 - Ea) * (1 - Ca)
// http://www.w3.org/TR/SVG11/masking.html#SimpleAlphaBlending
// https://www.w3.org/TR/SVG11/masking.html#SimpleAlphaBlending
var sourceOpacity = 1 - Math.sqrt(1 - opacity);
this.options.styles.track.opacity = sourceOpacity;

View file

@ -8,7 +8,7 @@ BR.Search = L.Control.Geocoder.extend({
onAdd: function (map) {
map.attributionControl.addAttribution(
'search by <a href="http://wiki.openstreetmap.org/wiki/Nominatim" target="_blank">Nominatim</a>');
'search by <a href="https://wiki.openstreetmap.org/wiki/Nominatim" target="_blank">Nominatim</a>');
return L.Control.Geocoder.prototype.onAdd.call(this, map);
},

View file

@ -0,0 +1,239 @@
(function(window) {
var HAS_HASHCHANGE = (function() {
var doc_mode = window.documentMode;
return ('onhashchange' in window) &&
(doc_mode === undefined || doc_mode > 7);
})();
L.Hash = function(map, options) {
this.onHashChange = L.Util.bind(this.onHashChange, this);
if (map) {
this.init(map, options);
}
};
L.Hash.parseHash = function(hash) {
if(hash.indexOf('#map=') === 0) {
hash = hash.substr(5);
}
var args = hash.split(/\&(.+)/);
var mapsArgs = args[0].split("/");
if (mapsArgs.length == 4) {
var zoom = parseInt(mapsArgs[0], 10),
lat = parseFloat(mapsArgs[1]),
lon = parseFloat(mapsArgs[2]),
layers = decodeURIComponent(mapsArgs[3]).split('-'),
additional = args[1];
if (isNaN(zoom) || isNaN(lat) || isNaN(lon)) {
return false;
} else {
return {
center: new L.LatLng(lat, lon),
zoom: zoom,
layers: layers,
additional: additional
};
}
} else {
return false;
}
};
L.Hash.formatHash = function(map) {
var center = map.getCenter(),
zoom = map.getZoom(),
precision = Math.max(0, Math.ceil(Math.log(zoom) / Math.LN2)),
layers = [];
//console.log(this.options);
var options = this.options;
//Check active layers
for(var key in options) {
if (options.hasOwnProperty(key)) {
if (map.hasLayer(options[key])) {
layers.push(key);
};
};
};
if (layers.length == 0) {
layers.push(Object.keys(options)[0]);
}
var params = [
zoom,
center.lat.toFixed(precision),
center.lng.toFixed(precision),
encodeURIComponent(layers.join("-"))
];
url = "#map=" + params.join("/");
if (this.additionalCb != null) {
var additional = this.additionalCb();
if (additional != null) {
return url + additional;
}
}
return url;
},
L.Hash.prototype = {
map: null,
lastHash: null,
parseHash: L.Hash.parseHash,
formatHash: L.Hash.formatHash,
init: function(map, options) {
this.map = map;
L.Util.setOptions(this, options);
// reset the hash
this.lastHash = null;
this.onHashChange();
if (!this.isListening) {
this.startListening();
}
},
removeFrom: function(map) {
if (this.changeTimeout) {
clearTimeout(this.changeTimeout);
}
if (this.isListening) {
this.stopListening();
}
this.map = null;
},
onMapMove: function() {
// bail if we're moving the map (updating from a hash),
// or if the map is not yet loaded
if (this.movingMap || !this.map._loaded) {
return false;
}
var hash = this.formatHash(this.map);
if (this.lastHash != hash) {
location.replace(hash);
this.lastHash = hash;
}
},
movingMap: false,
update: function() {
var hash = location.hash;
if (hash === this.lastHash) {
return;
}
var parsed = this.parseHash(hash);
if (!parsed) {
// migration from old hash style to new one
if (this.onInvalidHashChangeCb != null) {
var newHash = this.onInvalidHashChangeCb(hash);
if (newHash != null && newHash != hash) {
parsed = this.parseHash(newHash);
}
}
}
if (parsed) {
this.movingMap = true;
this.map.setView(parsed.center, parsed.zoom);
var layers = parsed.layers,
options = this.options,
that = this;
//Add/remove layer
this.map.eachLayer(function(layer) {
for (alayer in that.layers) {
if (that.layers[alayer] == layer) {
that.map.removeLayer(layer);
break;
}
}
});
var added = false;
layers.forEach(function(element, index, array) {
if (element in options) {
added = true;
that.map.addLayer(options[element]);
}
});
if (!added) {
// if we couldn't add layers (custom ones or invalid name), add the default one
this.map.addLayer(options[Object.keys(options)[0]]);
}
if (this.onHashChangeCb != null) {
this.onHashChangeCb(parsed.additional);
}
this.movingMap = false;
} else {
this.onMapMove(this.map);
}
},
// defer hash change updates every 100ms
changeDefer: 100,
changeTimeout: null,
onHashChange: function() {
// throttle calls to update() so that they only happen every
// `changeDefer` ms
if (!this.changeTimeout) {
var that = this;
this.changeTimeout = setTimeout(function() {
that.update();
that.changeTimeout = null;
}, this.changeDefer);
}
},
isListening: false,
hashChangeInterval: null,
startListening: function() {
this.map.on("moveend layeradd layerremove", this.onMapMove, this);
if (HAS_HASHCHANGE) {
L.DomEvent.addListener(window, "hashchange", this.onHashChange);
} else {
clearInterval(this.hashChangeInterval);
this.hashChangeInterval = setInterval(this.onHashChange, 50);
}
this.isListening = true;
},
stopListening: function() {
this.map.off("moveend layeradd layerremove", this.onMapMove, this);
if (HAS_HASHCHANGE) {
L.DomEvent.removeListener(window, "hashchange", this.onHashChange);
} else {
clearInterval(this.hashChangeInterval);
}
this.isListening = false;
},
_keyByValue: function(obj, value) {
for(var key in obj) {
if (obj.hasOwnProperty(key)) {
if (obj[key] === value) {
return key;
} else { return null; };
};
};
}
};
L.hash = function(map, options) {
return new L.Hash(map, options);
};
L.Map.prototype.addHash = function() {
this._hash = L.hash(this, this.options);
};
L.Map.prototype.removeHash = function() {
this._hash.removeFrom();
};
})(window);

View file

@ -2,19 +2,17 @@ L.BRouter = L.Class.extend({
statics: {
// NOTE: the routing API used here is not public!
// /brouter?lonlats=1.1,1.2|2.1,2.2|3.1,3.2|4.1,4.2&nogos=-1.1,-1.2,1|-2.1,-2.2,2&profile=shortest&alternativeidx=1&format=kml
URL_TEMPLATE: BR.conf.host + '/brouter?lonlats={lonlats}&nogos={nogos}&profile={profile}&alternativeidx={alternativeidx}&format={format}',
URL_TEMPLATE: '/brouter?lonlats={lonlats}&nogos={nogos}&profile={profile}&alternativeidx={alternativeidx}&format={format}',
URL_PROFILE_UPLOAD: BR.conf.host + '/brouter/profile',
PRECISION: 6,
NUMBER_SEPARATOR: ',',
GROUP_SEPARATOR: '|',
ABORTED_ERROR: 'aborted'
},
options: {
},
format: 'geojson',
initialize: function (options) {
L.setOptions(this, options);
@ -38,13 +36,30 @@ L.BRouter = L.Class.extend({
},
getUrlParams: function(latLngs, format) {
return {
lonlats: this._getLonLatsString(latLngs),
nogos: this._getNogosString(this.options.nogos),
profile: this.options.profile,
alternativeidx: this.options.alternative,
format: format || this.format
};
params = {};
if (this._getLonLatsString(latLngs) != null)
params.lonlats = this._getLonLatsString(latLngs);
if (this._getNogosString(this.options.nogos).length > 0)
params.nogos = this._getNogosString(this.options.nogos);
if (this.options.profile != null)
params.profile = this.options.profile;
params.alternativeidx = this.options.alternative;
if (format != null) {
params.format = format;
} else {
// do not put values in URL if this is the default value (format===null)
if (params.profile === BR.conf.profiles[0])
delete params.profile;
if (params.alternativeidx == 0)
delete params.alternativeidx;
}
return params;
},
parseUrlParams: function(params) {
@ -66,12 +81,26 @@ L.BRouter = L.Class.extend({
getUrl: function(latLngs, format) {
var urlParams = this.getUrlParams(latLngs, format);
var url = L.Util.template(L.BRouter.URL_TEMPLATE, urlParams);
return url;
var args = []
if (urlParams.lonlats != null && urlParams.lonlats.length > 0)
args.push(L.Util.template('lonlats={lonlats}', urlParams));
if (urlParams.nogos != null)
args.push(L.Util.template('nogos={nogos}', urlParams));
if (urlParams.profile != null)
args.push(L.Util.template('profile={profile}', urlParams));
if (urlParams.alternativeidx != null)
args.push(L.Util.template('alternativeidx={alternativeidx}', urlParams));
if (urlParams.format != null)
args.push(L.Util.template('format={format}', urlParams));
var prepend_host = (format != null);
return (prepend_host ? BR.conf.host : '') + '/brouter?' + args.join('&');
},
getRoute: function(latLngs, cb) {
var url = this.getUrl(latLngs),
var url = this.getUrl(latLngs, 'geojson'),
xhr = new XMLHttpRequest();
if (!url) {
@ -199,14 +228,14 @@ L.BRouter = L.Class.extend({
if (!s) {
return nogos;
}
groups = s.split(L.BRouter.GROUP_SEPARATOR);
for (var i = 0; i < groups.length; i++) {
// lng,lat,radius
numbers = groups[i].split(L.BRouter.NUMBER_SEPARATOR);
// TODO refactor: pass simple obj, create circle in NogoAreas; use shapeOptions of instance
// [lat,lng],radius
nogos.push(L.circle([numbers[1], numbers[0]], numbers[2], L.Draw.Circle.prototype.options.shapeOptions));
nogos.push(L.circle([numbers[1], numbers[0]], {radius: numbers[2]}));
}
return nogos;