Merge pull request #226 from bagage/222-add-users-poi

export user's POI (point of interest)
This commit is contained in:
Norbert Renner 2019-10-10 22:17:44 +02:00 committed by GitHub
commit ddf8e27085
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 260 additions and 35 deletions

1
.gitignore vendored
View file

@ -7,3 +7,4 @@ nbproject/
/dist
brouter-web.*.zip
yarn-error.log
package-lock.json

View file

@ -167,6 +167,9 @@ input#trackname:focus:invalid {
.routing-draw-enabled {
cursor: crosshair;
}
.pois-draw-enabled {
cursor: cell;
}
#map {
/* center error message horizontally */

View file

@ -165,6 +165,7 @@ gulp.task('watch', function() {
remember.forget('scripts', event.path);
}
});
gulp.watch(paths.locales, gulp.series('locales', 'reload'));
gulp.watch(paths.styles, gulp.series('styles', 'reload'));
gulp.watch(paths.layersConfig, gulp.series('layers_config', 'reload'));
gulp.watch(
@ -179,18 +180,16 @@ gulp.task('watch', function() {
// Print paths to console, for manually debugging the gulp build
// (comment out corresponding line of paths to print)
gulp.task('log', function() {
//return gulp.src(paths.scripts)
//return gulp.src(paths.styles)
//return gulp.src(paths.images)
// return gulp.src(paths.locales)
return gulp
.src(
paths.scripts
// var src = paths.scripts
// var src = paths.styles
// var src = paths.images
// var src = paths.locales
var src = paths.scripts
.concat(paths.styles)
.concat(paths.images)
.concat(paths.locales)
)
.pipe(gulpDebug());
.concat(paths.locales);
return gulp.src(src).pipe(gulpDebug());
});
gulp.task('inject', function() {

View file

@ -1,8 +1,9 @@
BR.Export = L.Class.extend({
latLngs: [],
initialize: function(router) {
initialize: function(router, pois) {
this.router = router;
this.pois = pois;
this.exportButton = $('#exportButton');
var trackname = (this.trackname = document.getElementById('trackname'));
this.tracknameAllowedChars = BR.conf.tracknameAllowedChars;
@ -38,7 +39,7 @@ BR.Export = L.Class.extend({
var name = encodeURIComponent(exportForm['trackname'].value);
var includeWaypoints = exportForm['include-waypoints'].checked;
var uri = this.router.getUrl(this.latLngs, format, name, includeWaypoints);
var uri = this.router.getUrl(this.latLngs, this.pois.getMarkers(), format, name, includeWaypoints);
var evt = document.createEvent('MouseEvents');
evt.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);

View file

@ -32,9 +32,8 @@
sidebar,
drawButton,
deleteRouteButton,
drawToolbar,
pois,
urlHash,
reverseRoute,
saveWarningShown = false;
// By default bootstrap-select use glyphicons
@ -73,7 +72,7 @@
]
});
reverseRouteButton = L.easyButton(
var reverseRouteButton = L.easyButton(
'fa-random',
function() {
routing.reverse();
@ -81,7 +80,7 @@
i18next.t('map.reverse-route')
);
deletePointButton = L.easyButton(
var deletePointButton = L.easyButton(
'<span><i class="fa fa-caret-left"></i><i class="fa fa-map-marker" style="margin-left: 1px; color: gray;"></i></span>',
function() {
routing.removeWaypoint(routing.getLast(), function(err, data) {});
@ -94,7 +93,7 @@
function() {
bootbox.prompt({
size: 'small',
title: i18next.t('map.delete-route-nogos'),
title: i18next.t('map.clear-route'),
inputType: 'checkbox',
inputOptions: [
{
@ -104,6 +103,10 @@
{
text: i18next.t('map.delete-nogo-areas'),
value: 'nogo'
},
{
text: i18next.t('map.delete-pois'),
value: 'pois'
}
],
value: ['route'],
@ -115,13 +118,16 @@
if (result.indexOf('nogo') !== -1) {
nogos.clear();
}
if (result.indexOf('pois') !== -1) {
pois.clear();
}
onUpdate();
urlHash.onMapMove();
}
}
});
},
i18next.t('map.delete-route-nogos')
i18next.t('map.clear-route')
);
function updateRoute(evt) {
@ -161,7 +167,6 @@
} else {
stats = new BR.TrackStats();
}
exportRoute = new BR.Export(router);
elevation = new BR.Elevation();
profile = new BR.Profile();
@ -208,6 +213,12 @@
styles: BR.conf.routingStyles
});
pois = new BR.PoiMarkers({
routing: routing
});
exportRoute = new BR.Export(router, pois);
routing.on('routing:routeWaypointEnd routing:setWaypointsEnd', function(evt) {
search.clear();
onUpdate(evt && evt.err);
@ -250,6 +261,8 @@
elevation.addBelow(map);
pois.addTo(map);
sidebar = BR.sidebar({
defaultTabId: BR.conf.transit ? 'tab_itinerary' : 'tab_profile',
listeningTabs: {
@ -262,13 +275,7 @@
}
nogos.addTo(map);
drawToolbar = L.easyBar([
drawButton,
reverseRouteButton,
nogos.getButton(),
deletePointButton,
deleteRouteButton
]).addTo(map);
L.easyBar([drawButton, reverseRouteButton, nogos.getButton(), deletePointButton, deleteRouteButton]).addTo(map);
nogos.preventRoutePointOnCreate(routing);
if (BR.keys.strava) {
@ -313,6 +320,7 @@
return p;
};
if (url == null) return;
var opts = router.parseUrlParams(url2params(url));
router.setOptions(opts);
routingOptions.setOptions(opts);
@ -324,6 +332,10 @@
routing.clear();
routing.setWaypoints(opts.lonlats);
}
if (opts.pois) {
pois.setMarkers(opts.pois);
}
};
var onInvalidHashChangeCb = function(params) {
@ -336,9 +348,13 @@
// do not initialize immediately
urlHash = new L.Hash(null, null);
// this callback is used to append anything in URL after L.Hash wrote #map=zoom/lat/lng/layer
urlHash.additionalCb = function() {
var url = router.getUrl(routing.getWaypoints(), null).substr('brouter?'.length + 1);
var url = router.getUrl(routing.getWaypoints(), pois.getMarkers(), null).substr('brouter?'.length + 1);
// by default brouter use | as separator. To make URL more human-readable, we remplace them with ; for users
url = url.replace(/\|/g, ';');
return url.length > 0 ? '&' + url : null;
};
urlHash.onHashChangeCb = onHashChangeCb;
@ -355,6 +371,7 @@
routingOptions.on('update', urlHash.onMapMove, urlHash);
nogos.on('update', urlHash.onMapMove, urlHash);
pois.on('update', urlHash.onMapMove, urlHash);
// waypoint add, move, delete (but last)
routing.on('routing:routeWaypointEnd', urlHash.onMapMove, urlHash);
// delete last waypoint
@ -403,6 +420,8 @@
});
}
L.AwesomeMarkers.Icon.prototype.options.prefix = 'fa';
i18next
.use(window.i18nextXHRBackend)
.use(window.i18nextBrowserLanguageDetector)

147
js/plugin/POIMarkers.js Normal file
View file

@ -0,0 +1,147 @@
BR.PoiMarkers = L.Control.extend({
markersLayer: null,
options: {
routing: null,
shortcut: {
draw: {
enable: 80, // char code for 'p'
disable: 27 // char code for 'ESC'
}
}
},
onAdd: function(map) {
var self = this;
this.map = map;
this.markersLayer = L.layerGroup([]).addTo(map);
this.drawButton = L.easyButton({
states: [
{
stateName: 'activate-poi',
icon: 'fa-hand-o-right',
onClick: function() {
self.draw(true);
},
title: i18next.t('map.draw-poi-start')
},
{
stateName: 'deactivate-poi',
icon: 'fa-hand-o-right active',
onClick: function() {
self.draw(false);
},
title: i18next.t('map.draw-poi-stop')
}
]
}).addTo(map);
map.on('routing:draw-start', function() {
self.draw(false);
});
var container = new L.DomUtil.create('div');
// keys not working when map container does not have focus, use document instead
L.DomEvent.removeListener(container, 'keyup', this._keyupListener);
L.DomEvent.addListener(document, 'keyup', this._keyupListener, this);
return container;
},
draw: function(enable) {
this.drawButton.state(enable ? 'deactivate-poi' : 'activate-poi');
if (enable) {
this.options.routing.draw(false);
this.map.on('click', this.onMapClick, this);
L.DomUtil.addClass(this.map.getContainer(), 'pois-draw-enabled');
} else {
this.map.off('click', this.onMapClick, this);
L.DomUtil.removeClass(this.map.getContainer(), 'pois-draw-enabled');
}
},
_keyupListener: function(e) {
// Suppress shortcut handling when a text input field is focussed
if (document.activeElement.type == 'text' || document.activeElement.type == 'textarea') {
return;
}
if (e.keyCode === this.options.shortcut.draw.disable) {
this.draw(false);
} else if (e.keyCode === this.options.shortcut.draw.enable) {
this.draw(true);
}
},
onMapClick: function(e) {
var self = this;
bootbox.prompt({
title: i18next.t('map.enter-poi-name'),
callback: function(result) {
if (result !== null) {
self.addMarker(e.latlng, result);
}
}
});
},
addMarker: function(latlng, name) {
// this method must only be used to sanitize for textContent.
// do NOT use it to sanitize any attribute,
// see https://web.archive.org/web/20121208091505/http://benv.ca/2012/10/4/you-are-probably-misusing-DOM-text-methods/
var sanitizeHTMLContent = function(str) {
var temp = document.createElement('div');
temp.textContent = str;
return temp.innerHTML;
};
var icon = L.AwesomeMarkers.icon({
icon: 'star',
markerColor: 'cadetblue'
});
var content = sanitizeHTMLContent(name) + '<br>';
content += "<button id='remove-poi-marker' class='btn btn-secondary'><i class='fa fa-trash'></i></button>";
var self = this;
var marker = L.marker(latlng, { icon: icon, draggable: true, name: name })
.bindPopup(content)
.on('dragend', function() {
self.fire('update');
})
.on('popupopen', function() {
$('#remove-poi-marker').on('click', function(e) {
self.markersLayer.removeLayer(marker);
e.preventDefault();
self.fire('update');
});
})
.addTo(this.markersLayer);
},
clear: function() {
this.markersLayer.clearLayers();
},
setMarkers: function(latLngNames) {
this.clear();
if (!latLngNames) return;
for (var i = 0; i < latLngNames.length; i++) {
var r = latLngNames[i];
this.addMarker(r.latlng, r.name);
}
},
getMarkers: function() {
return this.markersLayer.getLayers().map(function(it) {
return {
latlng: it._latlng,
name: it.options.name
};
});
}
});
BR.PoiMarkers.include(L.Evented.prototype);

View file

@ -38,7 +38,7 @@ L.BRouter = L.Class.extend({
L.setOptions(this, options);
},
getUrlParams: function(latLngs, format) {
getUrlParams: function(latLngs, pois, format) {
params = {};
if (this._getLonLatsString(latLngs) != null) params.lonlats = this._getLonLatsString(latLngs);
@ -53,6 +53,8 @@ L.BRouter = L.Class.extend({
if (this.options.profile != null) params.profile = this.options.profile;
if (pois && this._getLonLatsNameString(pois) != null) params.pois = this._getLonLatsNameString(pois);
params.alternativeidx = this.options.alternative;
if (format != null) {
@ -91,15 +93,18 @@ L.BRouter = L.Class.extend({
if (params.profile) {
opts.profile = params.profile;
}
if (params.pois) {
opts.pois = this._parseLonLatNames(params.pois);
}
return opts;
},
getUrl: function(latLngs, format, trackname, exportWaypoints) {
var urlParams = this.getUrlParams(latLngs, format);
getUrl: function(latLngs, pois, format, trackname, exportWaypoints) {
var urlParams = this.getUrlParams(latLngs, pois, format);
var args = [];
if (urlParams.lonlats != null && urlParams.lonlats.length > 0)
args.push(L.Util.template('lonlats={lonlats}', urlParams));
if (urlParams.pois != null && urlParams.pois.length > 0) args.push(L.Util.template('pois={pois}', urlParams));
if (urlParams.nogos != null) args.push(L.Util.template('nogos={nogos}', urlParams));
if (urlParams.polylines != null) args.push(L.Util.template('polylines={polylines}', urlParams));
if (urlParams.polygons != null) args.push(L.Util.template('polygons={polygons}', urlParams));
@ -120,7 +125,7 @@ L.BRouter = L.Class.extend({
},
getRoute: function(latLngs, cb) {
var url = this.getUrl(latLngs, 'geojson'),
var url = this.getUrl(latLngs, null, 'geojson'),
xhr = new XMLHttpRequest();
if (!url) {
@ -280,6 +285,39 @@ L.BRouter = L.Class.extend({
return lonlats;
},
_getLonLatsNameString: function(latLngNames) {
var s = '';
for (var i = 0; i < latLngNames.length; i++) {
s += this._formatLatLng(latLngNames[i].latlng);
s += L.BRouter.NUMBER_SEPARATOR;
s += encodeURIComponent(latLngNames[i].name);
if (i < latLngNames.length - 1) {
s += L.BRouter.GROUP_SEPARATOR;
}
}
return s;
},
_parseLonLatNames: function(s) {
var groups,
part,
lonlatnames = [];
if (!s) {
return lonlatnames;
}
groups = s.split(L.BRouter.GROUP_SEPARATOR);
for (var i = 0; i < groups.length; i++) {
// lng,lat,name
part = groups[i].split(L.BRouter.NUMBER_SEPARATOR);
lonlatnames.push({ latlng: L.latLng(part[1], part[0]), name: decodeURIComponent(part[2]) });
}
return lonlatnames;
},
_getNogosString: function(nogos) {
var s = '';
for (var i = 0, circle; i < nogos.length; i++) {

View file

@ -76,14 +76,18 @@
"map": {
"attribution-osm-long": "OpenStreetMap contributors",
"attribution-osm-short": "OpenStreetMap",
"clear-route": "Clear route data",
"copyright": "Copyright",
"cycling": "Cycling",
"delete-last-point": "Delete last point",
"delete-nogo-areas": "Delete all no-go areas",
"delete-pois": "Delete all points of interest",
"delete-route": "Delete route",
"delete-route-nogos": "Delete route and nogos",
"draw-poi-start": "Draw points of interest (P key)",
"draw-poi-stop": "Stop drawing points of interest (ESC key)",
"draw-route-start": "Draw route (D key)",
"draw-route-stop": "Stop drawing route (ESC key)",
"enter-poi-name": "Enter Point of Interest name",
"hikebike-hillshading": "Hillshading",
"hiking": "Hiking",
"layer": {

View file

@ -56,6 +56,7 @@
"leaflet-routing": "nrenner/leaflet-routing#dev",
"leaflet-sidebar-v2": "nrenner/leaflet-sidebar-v2#dev",
"leaflet-triangle-marker": "^1.0.1",
"leaflet.awesome-markers": "^2.0.5",
"leaflet.locatecontrol": "^0.60.0",
"leaflet.snogylop": "^0.4.0",
"leaflet.stravasegments": "2.3.2",
@ -179,6 +180,13 @@
"leaflet.stravasegments": {
"main": "dist/index.js"
},
"leaflet.awesome-markers": {
"main": [
"dist/leaflet.awesome-markers.js",
"dist/leaflet.awesome-markers.css",
"dist/images/*.png"
]
},
"font-awesome": {
"main": [
"css/font-awesome.css",

View file

@ -4488,6 +4488,11 @@ leaflet-triangle-marker@^1.0.1:
resolved "https://registry.yarnpkg.com/leaflet-triangle-marker/-/leaflet-triangle-marker-1.0.1.tgz#0775ee4903c6c0b71b20023dfb295dfc026bc23d"
integrity sha512-nK2Wtp5tUPwg9STrE78oKLQJvcDZTMU5i+4la1zhHZKZcjoTl9oVVd0f6keMx+wN70IiHsoDkHCFzIiVcCs9eQ==
leaflet.awesome-markers@^2.0.5:
version "2.0.5"
resolved "https://registry.yarnpkg.com/leaflet.awesome-markers/-/leaflet.awesome-markers-2.0.5.tgz#b7b0210d87e2566359bf478c1ab3ab07c7246f30"
integrity sha512-Ne/xDjkGyaujwNVVkv2tyXQUV0ZW7gZ0Mo0FuQY4jp2qWrvXi0hwDBvmZyF/8YOvybyMabTMM/mFWCTd1jZIQA==
leaflet.locatecontrol@^0.60.0:
version "0.60.0"
resolved "https://registry.yarnpkg.com/leaflet.locatecontrol/-/leaflet.locatecontrol-0.60.0.tgz#fc7be657ca9b7e8b8ba7263e52b0bb902b7cd965"