kopia lustrzana https://github.com/FacilMap/facilmap
Basic support to calculate routes using search form
rodzic
0a1dbf4461
commit
30fe847ba4
|
@ -0,0 +1,17 @@
|
|||
<div class="content container-fluid">
|
||||
<h2>{{route.short_name}}</h2>
|
||||
|
||||
<dl class="dl-horizontal">
|
||||
<dt class="distance">Distance</dt>
|
||||
<dd class="distance">{{route.distance | fpRound:2}} km ({{route.time | fpFormatTime}} h {{route.routeMode | fpRoutingMode}})</dd>
|
||||
</dl>
|
||||
</div>
|
||||
<div class="buttons" ng-if="!readonly">
|
||||
<div uib-dropdown ng-if="(types | fpPropertyCount:{type:'line'}) > 1">
|
||||
<button id="add-type-button" type="button" class="btn btn-default" uib-dropdown-toggle>Add to map <span class="caret"></span></button>
|
||||
<ul class="dropdown-menu" uib-dropdown-menu role="menu" aria-labelledby="add-type-button" uib-dropdown-menu>
|
||||
<li role="menuitem" ng-repeat="type in types | fpObjectFilter:{type:'line'}"><a href="#" ng-click="addToMap(type)">{{type.name}}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<button ng-if="(types | fpPropertyCount:{type:'line'}) == 1" class="btn btn-default" ng-click="addToMap()">Add to map</button>
|
||||
</div>
|
|
@ -0,0 +1,47 @@
|
|||
<div class="fp-search panel panel-default" ng-class="{'fp-hasResults': routes.length > 0}">
|
||||
<div class="panel-body">
|
||||
<form ng-submit="route()" ui-sortable="sortableOptions" ng-model="destinations">
|
||||
<div class="form-group" ng-repeat="destination in destinations">
|
||||
<div class="input-group">
|
||||
<span class="input-group-addon">
|
||||
<a href="javascript:" class="sort-handle"><span class="glyphicon glyphicon-resize-vertical"></span></a>
|
||||
<a href="javascript:" ng-click="removeDestination($index)" ng-show="destinations.length > 2"><span class="glyphicon glyphicon-minus"></span></a>
|
||||
</span>
|
||||
<div class="has-feedback">
|
||||
<input type="search" class="form-control" ng-model="destination.query" placeholder="{{$index == 0 ? 'From' : $index == destinations.length-1 ? 'To' : 'Via'}}" tabindex="{{$index+1}}">
|
||||
<a href="javascript:" class="reset-button form-control-feedback" ng-click="destination.query=''" ng-show="destination.query.length > 0"><span class="icon-clear"></span></a>
|
||||
</div>
|
||||
<span class="input-group-btn" uib-dropdown ng-show="destination.query.length > 0">
|
||||
<button type="button" class="btn btn-default" uib-dropdown-toggle ng-click="loadSuggestions(destination)"><span class="caret"></span></button>
|
||||
<ul class="dropdown-menu" role="menu" uib-dropdown-menu>
|
||||
<li ng-repeat="suggestion in destination.suggestions" ng-class="{active: destination.selectedSuggestionIdx == $index}"><a href="javascript:" ng-click="destination.selectedSuggestionIdx = $index; reroute()">{{suggestion.display_name}} ({{suggestion.type}})</a></li>
|
||||
</ul>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button type="button" class="btn btn-default" ng-click="addDestination()"><span class="glyphicon glyphicon-plus"></span></button>
|
||||
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn btn-default" uib-btn-radio="'car'" ng-model="routeMode" tabindex="{{destinations.length+1}}" ng-click="reroute()"><span class="icon-car"></span></button>
|
||||
<button type="button" class="btn btn-default" uib-btn-radio="'bicycle'" ng-model="routeMode" tabindex="{{destinations.length+2}}" ng-click="reroute()"><span class="icon-bicycle"></span></button>
|
||||
<button type="button" class="btn btn-default" uib-btn-radio="'pedestrian'" ng-model="routeMode" tabindex="{{destinations.length+3}}" ng-click="reroute()"><span class="icon-walk"></span></button>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary" tabindex="{{destinations.length+4}}">Go!</button>
|
||||
|
||||
<button type="button" class="btn btn-default pull-right active" ng-click="showSearchForm()"><span class="glyphicon glyphicon-road"></span></button>
|
||||
</div>
|
||||
|
||||
<div class="fp-search-results" ng-show="routes || routeError">
|
||||
<div uib-alert class="alert-danger no-results" ng-if="routeError">{{routeError}}</div>
|
||||
|
||||
<ul class="list-group" ng-if="routes.length > 0">
|
||||
<li ng-repeat="route in routes" class="list-group-item" ng-class="{ active: activeRouteIdx == $index }">
|
||||
<a href="javascript:" ng-click="setActiveRoute($index)">{{route.display_name}}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,213 @@
|
|||
(function(fp, $, ng, undefined) {
|
||||
|
||||
fp.app.factory("fpMapSearchRoute", function($rootScope, $templateCache, $compile, fpUtils, L, $timeout, $q) {
|
||||
return function(map, searchUi) {
|
||||
var activeStyle = {
|
||||
color : '#0000ff',
|
||||
weight : 8,
|
||||
opacity : 0.7
|
||||
};
|
||||
|
||||
var inactiveStyle = {
|
||||
color : '#0000ff',
|
||||
weight : 6,
|
||||
opacity : 0.3
|
||||
};
|
||||
|
||||
var scope = $rootScope.$new(true);
|
||||
|
||||
scope.routeMode = 'car';
|
||||
scope.destinations = [ ];
|
||||
|
||||
scope.sortableOptions = ng.copy($rootScope.sortableOptions);
|
||||
scope.sortableOptions.update = function() {
|
||||
scope.reroute();
|
||||
};
|
||||
|
||||
scope.addDestination = function() {
|
||||
scope.destinations.push({
|
||||
query: "",
|
||||
suggestions: [ ]
|
||||
});
|
||||
};
|
||||
|
||||
scope.addDestination();
|
||||
scope.addDestination();
|
||||
|
||||
scope.removeDestination = function(idx) {
|
||||
scope.destinations.splice(idx, 1);
|
||||
};
|
||||
|
||||
scope.showSearchForm = function() {
|
||||
routeUi.hide();
|
||||
searchUi.show();
|
||||
};
|
||||
|
||||
scope.loadSuggestions = function(destination) {
|
||||
return $q(function(resolve, reject) {
|
||||
if(destination.suggestionQuery == destination.query)
|
||||
return resolve();
|
||||
|
||||
destination.suggestions = [ ];
|
||||
destination.suggestionQuery = null;
|
||||
destination.selectedSuggestionIdx = null;
|
||||
if(destination.query.trim() != "") {
|
||||
var query = destination.query;
|
||||
|
||||
map.loadStart();
|
||||
map.socket.emit("find", { query: query }, function(err, results) {
|
||||
map.loadEnd();
|
||||
|
||||
if(err) {
|
||||
map.messages.showMessage("danger", err);
|
||||
return reject(err);
|
||||
}
|
||||
|
||||
destination.suggestions = results;
|
||||
destination.suggestionQuery = query;
|
||||
destination.selectedSuggestionIdx = 0;
|
||||
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
scope.route = function() {
|
||||
scope.reset();
|
||||
|
||||
$q.all(scope.destinations.map(scope.loadSuggestions)).then(function() {
|
||||
var points = scope.destinations.map(function(destination) {
|
||||
if(destination.suggestions.length == null)
|
||||
throw "No place has been found for search term “" + destination.query + "”.";
|
||||
|
||||
var sug = destination.suggestions[destination.selectedSuggestionIdx] || destination.suggestions[0];
|
||||
return { lat: sug.lat, lon: sug.lon };
|
||||
});
|
||||
|
||||
return $q(function(resolve, reject) {
|
||||
map.socket.emit("getRoutes", { destinations: points, mode: scope.routeMode }, function(err, res) {
|
||||
err ? reject(err) : resolve(res);
|
||||
});
|
||||
});
|
||||
}).then(function(routes) {
|
||||
routes.forEach(function(route, i) {
|
||||
route.short_name = "Option " + (i+1);
|
||||
route.display_name = route.short_name + " (" + fpUtils.round(route.distance, 2) + " km, " + fpUtils.formatTime(route.time) + " h)";
|
||||
route.routeMode = scope.routeMode;
|
||||
});
|
||||
|
||||
scope.routes = routes;
|
||||
scope.activeRouteIdx = 0;
|
||||
renderResults();
|
||||
}).catch(function(err) {
|
||||
scope.routeError = err;
|
||||
});
|
||||
};
|
||||
|
||||
scope.reroute = function() {
|
||||
if(scope.routes || scope.routeError)
|
||||
scope.route();
|
||||
};
|
||||
|
||||
scope.reset = function() {
|
||||
scope.routes = [ ];
|
||||
scope.routeError = null;
|
||||
scope.activeRouteIdx = null;
|
||||
};
|
||||
|
||||
scope.setActiveRoute = function(routeIdx) {
|
||||
scope.activeRouteIdx = routeIdx;
|
||||
updateStyle();
|
||||
};
|
||||
|
||||
var el = $($templateCache.get("map/search/search-route.html")).insertAfter(map.map.getContainer());
|
||||
$compile(el)(scope);
|
||||
scope.$evalAsync(); // $compile only replaces variables on next digest
|
||||
|
||||
var layerGroup = L.featureGroup([]).addTo(map.map);
|
||||
|
||||
function renderResults() {
|
||||
clearRenders();
|
||||
|
||||
scope.routes.forEach(function(route, i) {
|
||||
var layer = L.polyline(route.trackPoints.map(function(it) { return [ it.lat, it.lon ] }), i == scope.activeRouteIdx ? activeStyle : inactiveStyle)
|
||||
.bindPopup($("<div/>")[0], map.popupOptions)
|
||||
.on("popupopen", function(e) {
|
||||
scope.setActiveRoute(i);
|
||||
renderRoutePopup(route, e.popup);
|
||||
}.fpWrapApply(scope))
|
||||
.on("popupclose", function(e) {
|
||||
ng.element(e.popup.getContent()).scope().$destroy();
|
||||
})
|
||||
.bindTooltip(route.display_name, $.extend({}, map.tooltipOptions, { sticky: true, offset: [ 20, 0 ] }));
|
||||
|
||||
layerGroup.addLayer(layer);
|
||||
|
||||
if(i == scope.activeRouteIdx)
|
||||
layer.openPopup();
|
||||
});
|
||||
|
||||
map.map.flyToBounds(layerGroup.getBounds());
|
||||
}
|
||||
|
||||
function updateStyle() {
|
||||
layerGroup.getLayers().forEach(function(layer, i) {
|
||||
layer.setStyle(i == scope.activeRouteIdx ? activeStyle : inactiveStyle);
|
||||
|
||||
if(i == scope.activeRouteIdx)
|
||||
layer.openPopup();
|
||||
})
|
||||
}
|
||||
|
||||
function clearRenders() {
|
||||
layerGroup.clearLayers();
|
||||
}
|
||||
|
||||
function renderRoutePopup(route, popup) {
|
||||
var scope = map.socket.$new();
|
||||
|
||||
scope.route = route;
|
||||
|
||||
scope.addToMap = function(type) {
|
||||
if(type == null) {
|
||||
for(var i in map.socket.types) {
|
||||
if(map.socket.types[i].type == "line") {
|
||||
type = map.socket.types[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//map.markersUi.createMarker(result, type, { name: result.display_name });
|
||||
};
|
||||
|
||||
var el = popup.getContent();
|
||||
$(el).html($templateCache.get("map/search/route-popup.html"));
|
||||
$compile(el)(scope);
|
||||
|
||||
// Prevent popup close on button click
|
||||
$("button", el).click(function(e) {
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
$timeout(function() { $timeout(function() { // $compile only replaces variables on next digest
|
||||
popup.update();
|
||||
}); });
|
||||
}
|
||||
|
||||
var routeUi = {
|
||||
show: function() {
|
||||
el.show();
|
||||
},
|
||||
|
||||
hide: function() {
|
||||
el.hide();
|
||||
}
|
||||
};
|
||||
routeUi.hide();
|
||||
return routeUi;
|
||||
};
|
||||
});
|
||||
|
||||
})(FacilPad, jQuery, angular);
|
|
@ -13,6 +13,9 @@
|
|||
|
||||
.fp-search:hover,.fp-search.fp-hasFocus {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.fp-search/*.fp-hasFocus*/ {
|
||||
width: 350px;
|
||||
max-width: 40%;
|
||||
}
|
||||
|
@ -33,6 +36,15 @@
|
|||
margin: 10px 0 0;
|
||||
}
|
||||
|
||||
.fp-search .reset-button {
|
||||
z-index: 5;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.fp-search .active a {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
@media print {
|
||||
.fp-search {
|
||||
display: none;
|
||||
|
|
|
@ -1,16 +1,20 @@
|
|||
<div class="fp-search panel panel-default" ng-class="{'fp-hasResults': !!searchResults,'fp-hasFocus': !!hasFocus}">
|
||||
<div class="fp-search panel panel-default" ng-class="{'fp-hasResults': !!searchResults}">
|
||||
<div class="panel-body">
|
||||
<form ng-submit="search()">
|
||||
<div class="input-group has-feedback">
|
||||
<span class="input-group-btn" ng-show="searchString.length > 0">
|
||||
<button type="button" class="btn btn-default" ng-click="searchString=''; search()"><span class="glyphicon glyphicon-remove"></span></button>
|
||||
</span>
|
||||
<input type="search" class="form-control" ng-model="searchString" placeholder="Search" ng-focus="hasFocus=true" ng-blur="hasFocus=false">
|
||||
<span class="input-group-btn">
|
||||
<button type="submit" class="btn btn-default"><span class="glyphicon glyphicon-search"></span></button>
|
||||
</span>
|
||||
<div class="form-group">
|
||||
<div class="input-group">
|
||||
<div class="has-feedback">
|
||||
<input type="search" class="form-control" ng-model="searchString" placeholder="Search" tabindex="1">
|
||||
<a href="javascript:" class="reset-button form-control-feedback" ng-click="searchString=''; search()" ng-show="searchString.length > 0"><span class="icon-clear"></span></a>
|
||||
</div>
|
||||
<span class="input-group-btn">
|
||||
<button type="submit" class="btn btn-default"><span class="glyphicon glyphicon-search" tabindex="2"></span></button>
|
||||
<button type="button" class="btn btn-default" ng-click="showRoutingForm()" tabindex="3"><span class="glyphicon glyphicon-road"></span></button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="fp-search-results" ng-show="searchResults">
|
||||
<div uib-alert class="alert-danger no-results" ng-if="searchResults.length == 0">No results have been found.</div>
|
||||
<ul class="list-group" ng-if="searchResults.length > 0">
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
(function(fp, $, ng, undefined) {
|
||||
|
||||
fp.app.factory("fpMapSearch", function($rootScope, $templateCache, $compile, fpUtils, L, $timeout) {
|
||||
fp.app.factory("fpMapSearch", function($rootScope, $templateCache, $compile, fpUtils, L, $timeout, $q, fpMapSearchRoute) {
|
||||
return function(map) {
|
||||
var iconSuffix = ".n.32.png";
|
||||
|
||||
|
@ -54,6 +54,11 @@
|
|||
map.map.flyToBounds(layerGroup.getBounds());
|
||||
};
|
||||
|
||||
scope.showRoutingForm = function() {
|
||||
searchUi.hide();
|
||||
routeUi.show();
|
||||
};
|
||||
|
||||
scope.$watch("showAll", function() {
|
||||
if(!scope.searchResults)
|
||||
return;
|
||||
|
@ -150,7 +155,15 @@
|
|||
}); });
|
||||
}
|
||||
|
||||
var fpMapSearch = {
|
||||
var searchUi = {
|
||||
show: function() {
|
||||
el.show();
|
||||
},
|
||||
|
||||
hide: function() {
|
||||
el.hide();
|
||||
},
|
||||
|
||||
search: function(query) {
|
||||
if(query != null)
|
||||
scope.searchString = query;
|
||||
|
@ -162,7 +175,10 @@
|
|||
console.log("showFiles", files);
|
||||
}
|
||||
};
|
||||
return fpMapSearch;
|
||||
|
||||
var routeUi = fpMapSearchRoute(map, searchUi);
|
||||
|
||||
return searchUi;
|
||||
};
|
||||
});
|
||||
|
||||
|
|
|
@ -85,6 +85,7 @@
|
|||
switch(mode) {
|
||||
case "fastest":
|
||||
case "shortest":
|
||||
case "car":
|
||||
return "by car";
|
||||
case "bicycle":
|
||||
return "by bicycle";
|
||||
|
@ -251,4 +252,31 @@
|
|||
};
|
||||
});
|
||||
|
||||
fp.app.filter('fpNumberArray', function() {
|
||||
return function(value, key) {
|
||||
var ret = [ ];
|
||||
for(var i=0; i<value; i++)
|
||||
ret.push(i);
|
||||
return ret;
|
||||
};
|
||||
});
|
||||
|
||||
fp.app.filter('fpRound', function(fpUtils) {
|
||||
return function(value, key) {
|
||||
return fpUtils.round(value, key);
|
||||
};
|
||||
});
|
||||
|
||||
fp.app.filter('fpFormatTime', function(fpUtils) {
|
||||
return function(value, key) {
|
||||
return fpUtils.formatTime(value);
|
||||
};
|
||||
});
|
||||
|
||||
fp.app.filter('fpRoutingMode', function(fpUtils) {
|
||||
return function(value) {
|
||||
return fpUtils.routingMode(value);
|
||||
};
|
||||
});
|
||||
|
||||
})(FacilPad, jQuery, angular);
|
Plik binarny nie jest wyświetlany.
|
@ -0,0 +1,56 @@
|
|||
@font-face {
|
||||
font-family: 'fontello';
|
||||
src: url('fontello.ttf') format('truetype');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
/* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */
|
||||
/* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */
|
||||
/*
|
||||
@media screen and (-webkit-min-device-pixel-ratio:0) {
|
||||
@font-face {
|
||||
font-family: 'fontello';
|
||||
src: url('../font/fontello.svg?75993818#fontello') format('svg');
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
[class^="icon-"]:before, [class*=" icon-"]:before {
|
||||
font-family: "fontello";
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
speak: none;
|
||||
|
||||
display: inline-block;
|
||||
text-decoration: inherit;
|
||||
width: 1em;
|
||||
margin-right: .2em;
|
||||
text-align: center;
|
||||
/* opacity: .8; */
|
||||
|
||||
/* For safety - reset parent styles, that can break glyph codes*/
|
||||
font-variant: normal;
|
||||
text-transform: none;
|
||||
|
||||
/* fix buttons height, for twitter bootstrap */
|
||||
line-height: 1em;
|
||||
|
||||
/* Animation center compensation - margins should be symmetric */
|
||||
/* remove if not needed */
|
||||
margin-left: .2em;
|
||||
|
||||
/* you can be more comfortable with increased icons size */
|
||||
/* font-size: 120%; */
|
||||
|
||||
/* Font smoothing. That was taken from TWBS */
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
|
||||
/* Uncomment for 3D effect */
|
||||
/* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
|
||||
}
|
||||
|
||||
.icon-bicycle:before { content: '\f117'; } /* '' */
|
||||
.icon-car:before { content: '\f125'; } /* '' */
|
||||
.icon-clear:before { content: '\f135'; } /* '' */
|
||||
.icon-walk:before { content: '\f216'; } /* '' */
|
Plik binarny nie jest wyświetlany.
|
@ -21,7 +21,8 @@ var img64 = require("./gulpfile-img64");
|
|||
var files = [
|
||||
"app/**/*.js",
|
||||
"app/**/*.css",
|
||||
"app/**/*.html"
|
||||
"app/**/*.html",
|
||||
"assets/**/*.css"
|
||||
];
|
||||
|
||||
gulp.task("default", [ "index" ]);
|
||||
|
|
|
@ -15,18 +15,26 @@ var RESOLUTION_20 = 0.0000013411044763239684 * 4;
|
|||
var ROUTING_TYPES = {
|
||||
fastest: "driving",
|
||||
shortest: "driving",
|
||||
car: "driving",
|
||||
bicycle: "cycling",
|
||||
pedestrian: "walking"
|
||||
};
|
||||
|
||||
var ACCESS_TOKEN = "pk.eyJ1IjoiY2RhdXRoIiwiYSI6ImNpdTYwMmZwMDAwM3AyenBhemM5NHM4ZmgifQ.93z6yuzcsxt3eZk9NxPGHA";
|
||||
|
||||
function calculateRouting(points, mode) {
|
||||
function calculateRouting(points, mode, simple, multiple) {
|
||||
var coords = [ ];
|
||||
for(var i=0; i<points.length; i++)
|
||||
coords.push(points[i].lon + "," + points[i].lat);
|
||||
|
||||
var url = ROUTING_URL + "/" + ROUTING_TYPES[mode] + "/" + coords.join(";") + "?alternatives=true&steps=false&geometries=geojson&overview=full&annotations=false&access_token=" + encodeURIComponent(ACCESS_TOKEN);
|
||||
var url = ROUTING_URL + "/" + ROUTING_TYPES[mode] + "/" + coords.join(";")
|
||||
+ "?alternatives=" + (multiple ? "true" : "false")
|
||||
+ "&steps=false"
|
||||
+ "&geometries=geojson"
|
||||
+ "&overview=" + (simple ? "simplified" : "full")
|
||||
+ "&annotations=false"
|
||||
+ "&access_token=" + encodeURIComponent(ACCESS_TOKEN);
|
||||
|
||||
return request.get({
|
||||
url: url,
|
||||
json: true,
|
||||
|
@ -40,15 +48,19 @@ function calculateRouting(points, mode) {
|
|||
if(body.code != 'Ok')
|
||||
throw "Route could not be calculated (" + body.code + ").";
|
||||
|
||||
var ret = {
|
||||
trackPoints : body.routes[0].geometry.coordinates.map(function(it) { return { lat: it[1], lon: it[0] }; }),
|
||||
distance: body.routes[0].distance/1000,
|
||||
time: body.routes[0].duration
|
||||
};
|
||||
var ret = [ ];
|
||||
for(var i=0; i<(multiple ? body.routes.length : 1); i++) {
|
||||
ret[i] = {
|
||||
trackPoints : body.routes[i].geometry.coordinates.map(function(it) { return { lat: it[1], lon: it[0] }; }),
|
||||
distance: body.routes[i].distance/1000,
|
||||
time: body.routes[i].duration
|
||||
};
|
||||
|
||||
_calculateZoomLevels(ret.trackPoints);
|
||||
if(!simple)
|
||||
_calculateZoomLevels(ret[i].trackPoints);
|
||||
}
|
||||
|
||||
return ret;
|
||||
return multiple ? ret : ret[0];
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -277,6 +277,15 @@ var appP = Promise.denodeify(app.listen.bind(app))(config.port, config.host).the
|
|||
|
||||
return search.find(data.query);
|
||||
});
|
||||
},
|
||||
|
||||
getRoutes: function(data) {
|
||||
return Promise.resolve().then(function() {
|
||||
if(!utils.stripObject(data, { destinations: [ { lat: "number", lon: "number" } ], mode: "string" }))
|
||||
throw "Invalid parameters.";
|
||||
|
||||
return routing.calculateRouting(data.destinations, data.mode, true, true);
|
||||
});
|
||||
}
|
||||
|
||||
/*copyPad : function(data, callback) {
|
||||
|
|
Ładowanie…
Reference in New Issue