kopia lustrzana https://github.com/FacilMap/facilmap
344 wiersze
8.8 KiB
JavaScript
344 wiersze
8.8 KiB
JavaScript
import fm from '../app';
|
|
import $ from 'jquery';
|
|
import L from 'leaflet';
|
|
import ng from 'angular';
|
|
|
|
fm.app.factory("fmSearchRoute", function($rootScope, $compile, fmUtils, $timeout, $q, fmSortableOptions) {
|
|
return function(map, searchUi) {
|
|
var lineStyle = {
|
|
color : '#0000ff',
|
|
weight : 8,
|
|
opacity : 0.7
|
|
};
|
|
|
|
var dragTimeout = 300;
|
|
|
|
var scope = $rootScope.$new(true);
|
|
|
|
scope.client = map.client;
|
|
scope.routeMode = 'car';
|
|
scope.destinations = [ ];
|
|
scope.submittedQueries = null;
|
|
scope.submittedMode = null;
|
|
|
|
scope.sortableOptions = ng.copy(fmSortableOptions);
|
|
scope.sortableOptions.update = function() {
|
|
scope.reroute(true);
|
|
};
|
|
|
|
scope.addDestination = function() {
|
|
scope.destinations.push({
|
|
query: "",
|
|
loadingQuery: "",
|
|
loadedQuery: "",
|
|
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) {
|
|
if(destination.loadedQuery == destination.query)
|
|
return $q.resolve();
|
|
|
|
destination.suggestions = [ ];
|
|
var query = destination.loadingQuery = destination.query;
|
|
|
|
if(destination.query.trim() != "") {
|
|
return map.client.find({ query: query }).then(function(results) {
|
|
if(query != destination.loadingQuery)
|
|
return; // The destination has changed in the meantime
|
|
|
|
if(fmUtils.isSearchId(query) && results.length > 0 && results[0].display_name)
|
|
destination.query = query = results[0].display_name;
|
|
|
|
destination.suggestions = results;
|
|
destination.loadedQuery = query;
|
|
destination.selectedSuggestionIdx = 0;
|
|
}).catch(function(err) {
|
|
map.messages.showMessage("danger", err);
|
|
});
|
|
}
|
|
};
|
|
|
|
scope.route = function(dragging, noZoom) {
|
|
if(!dragging)
|
|
scope.reset();
|
|
|
|
if(scope.destinations[0].query.trim() == "" || scope.destinations[scope.destinations.length-1].query.trim() == "")
|
|
return;
|
|
|
|
var points;
|
|
var mode = scope.routeMode;
|
|
|
|
scope.submittedQueries = scope.destinations.map(function(destination) {
|
|
if(destination.loadedQuery == destination.query && destination.suggestions.length)
|
|
return destination.suggestions[destination.selectedSuggestionIdx].id || destination.suggestions[0].id;
|
|
else
|
|
return destination.query;
|
|
});
|
|
scope.submittedMode = mode;
|
|
|
|
map.mapEvents.$broadcast("searchchange");
|
|
|
|
return $q.all(scope.destinations.map(scope.loadSuggestions)).then(function() {
|
|
points = scope.destinations.filter(function(destination) {
|
|
return destination.query.trim() != "";
|
|
}).map(function(destination) {
|
|
if(destination.suggestions.length == 0)
|
|
throw "No place has been found for search term “" + destination.query + "”.";
|
|
|
|
return destination.suggestions[destination.selectedSuggestionIdx] || destination.suggestions[0];
|
|
});
|
|
|
|
scope.submittedQueries = points.map(function(point) {
|
|
return point.id;
|
|
});
|
|
|
|
map.mapEvents.$broadcast("searchchange");
|
|
|
|
return map.client.getRoute({ destinations: points.map(function(point) { return { lat: point.lat, lon: point.lon }; }), mode: mode });
|
|
}).then(function(route) {
|
|
route.routePoints = points;
|
|
route.routeMode = mode;
|
|
|
|
scope.routeObj = route;
|
|
scope.routeError = null;
|
|
renderRoute(dragging, noZoom);
|
|
}).catch(function(err) {
|
|
scope.routeError = err;
|
|
});
|
|
};
|
|
|
|
scope.reroute = function(noZoom) {
|
|
if(scope.routeObj || scope.routeError)
|
|
scope.route(false, noZoom);
|
|
};
|
|
|
|
scope.reset = function() {
|
|
scope.routeObj = null;
|
|
scope.routeError = null;
|
|
scope.submittedQueries = null;
|
|
scope.submittedMode = null;
|
|
|
|
clearRoute();
|
|
};
|
|
|
|
scope.clear = function() {
|
|
scope.reset();
|
|
|
|
scope.destinations = [ ];
|
|
scope.addDestination();
|
|
scope.addDestination();
|
|
};
|
|
|
|
scope.addToMap = function(type) {
|
|
if(type == null) {
|
|
for(var i in map.client.types) {
|
|
if(map.client.types[i].type == "line") {
|
|
type = map.client.types[i];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
map.linesUi.createLine(type, scope.routeObj.routePoints.map(function(point) { return { lat: point.lat, lon: point.lon }; }), { mode: scope.routeObj.routeMode });
|
|
|
|
scope.clear();
|
|
};
|
|
|
|
var el = $(require("./search-route.html")).insertAfter(searchUi._el);
|
|
$compile(el)(scope);
|
|
scope.$evalAsync(); // $compile only replaces variables on next digest
|
|
|
|
var routeLayer = null;
|
|
var dragMarker = null;
|
|
var markers = [ ];
|
|
var recalcRoute = fmUtils.minInterval(dragTimeout, false);
|
|
|
|
function renderRoute(dragging, noZoom) {
|
|
clearRoute(dragging);
|
|
|
|
routeLayer = L.polyline(scope.routeObj.trackPoints.map(function(it) { return [ it.lat, it.lon ] }), lineStyle).addTo(map.map);
|
|
map.map.almostOver.addLayer(routeLayer);
|
|
|
|
dragMarker = fmUtils.temporaryDragMarker(map.map, routeLayer, map.dragMarkerColour, function(marker) {
|
|
var latlng = marker.getLatLng();
|
|
var idx = fmUtils.getIndexOnLine(map.map, scope.routeObj.trackPoints, scope.routeObj.routePoints, { lat: latlng.lat, lon: latlng.lng });
|
|
|
|
scope.destinations.splice(idx, 0, makeCoordDestination(latlng));
|
|
markers.splice(idx, 0, marker);
|
|
|
|
registerMarkerHandlers(marker);
|
|
|
|
marker.once("dragend", updateMarkerColours);
|
|
|
|
scope.route(true);
|
|
}.fmWrapApply(scope));
|
|
|
|
if(!dragging) {
|
|
if(!noZoom)
|
|
map.map.flyToBounds(routeLayer.getBounds());
|
|
|
|
// Render markers
|
|
|
|
scope.routeObj.routePoints.forEach(function(point, i) {
|
|
var marker = L.marker([ point.lat, point.lon ], {
|
|
icon: fmUtils.createMarkerIcon(map.dragMarkerColour, 35),
|
|
draggable: true
|
|
}).addTo(map.map);
|
|
|
|
registerMarkerHandlers(marker);
|
|
|
|
markers.push(marker);
|
|
});
|
|
|
|
updateMarkerColours();
|
|
}
|
|
}
|
|
|
|
function registerMarkerHandlers(marker) {
|
|
marker.on("dblclick", function() {
|
|
scope.$apply(function() {
|
|
scope.removeDestination(markers.indexOf(marker));
|
|
scope.reroute(true);
|
|
});
|
|
})
|
|
.on("drag", function() {
|
|
recalcRoute(function() {
|
|
scope.destinations[markers.indexOf(marker)] = makeCoordDestination(marker.getLatLng());
|
|
|
|
return scope.route(true);
|
|
}.fmWrapApply(scope));
|
|
});
|
|
}
|
|
|
|
function updateMarkerColours() {
|
|
markers.forEach(function(marker, i) {
|
|
var colour = (i == 0 ? map.startMarkerColour : i == markers.length-1 ? map.endMarkerColour : map.dragMarkerColour);
|
|
|
|
marker.setIcon(fmUtils.createMarkerIcon(colour, 35));
|
|
});
|
|
}
|
|
|
|
function clearRoute(dragging) {
|
|
if(routeLayer) {
|
|
map.map.almostOver.removeLayer(routeLayer);
|
|
routeLayer.remove();
|
|
routeLayer = null;
|
|
}
|
|
|
|
if(dragMarker) {
|
|
dragMarker();
|
|
dragMarker = null;
|
|
}
|
|
|
|
if(!dragging) {
|
|
markers.forEach(function(marker) {
|
|
marker.remove();
|
|
});
|
|
markers = [ ];
|
|
}
|
|
}
|
|
|
|
function makeCoordDestination(latlng) {
|
|
var disp = fmUtils.round(latlng.lat, 5) + "," + fmUtils.round(latlng.lng, 5);
|
|
return {
|
|
query: disp,
|
|
loadingQuery: disp,
|
|
loadedQuery: disp,
|
|
selectedSuggestionIdx: 0,
|
|
suggestions: [ {
|
|
lat: latlng.lat,
|
|
lon: latlng.lng,
|
|
display_name: disp,
|
|
short_name: disp,
|
|
type: "coordinates",
|
|
id: disp
|
|
} ]
|
|
};
|
|
}
|
|
|
|
function _setDestination(dest, query, suggestions, selectedSuggestion) {
|
|
dest.query = query;
|
|
|
|
if(suggestions) {
|
|
dest.suggestions = suggestions;
|
|
dest.loadingQuery = dest.loadedQuery = query;
|
|
dest.selectedSuggestionIdx = Math.max(suggestions.indexOf(selectedSuggestion), 0);
|
|
}
|
|
}
|
|
|
|
var routeUi = {
|
|
show: function() {
|
|
el.show();
|
|
},
|
|
|
|
hide: function() {
|
|
scope.reset();
|
|
el.hide();
|
|
},
|
|
|
|
setQueries: function(queries) {
|
|
scope.clear();
|
|
|
|
for(var i=0; i<queries.length; i++) {
|
|
if(scope.destinations.length <= i)
|
|
scope.addDestination();
|
|
|
|
$.extend(scope.destinations[i], typeof queries[i] == "object" ? queries[i] : { query: queries[i] });
|
|
}
|
|
},
|
|
|
|
setFrom: function(from, suggestions, selectedSuggestion) {
|
|
_setDestination(scope.destinations[0], from, suggestions, selectedSuggestion);
|
|
},
|
|
|
|
addVia: function(via, suggestions, selectedSuggestion) {
|
|
scope.addDestination();
|
|
var newDest = scope.destinations.pop();
|
|
_setDestination(newDest, via, suggestions, selectedSuggestion);
|
|
scope.destinations.splice(scope.destinations.length-1, 0, newDest);
|
|
},
|
|
|
|
setTo: function(to, suggestions, selectedSuggestion) {
|
|
_setDestination(scope.destinations[scope.destinations.length-1], to, suggestions, selectedSuggestion);
|
|
},
|
|
|
|
setMode: function(mode) {
|
|
scope.routeMode = mode;
|
|
},
|
|
|
|
getQueries: function() {
|
|
return scope.submittedQueries;
|
|
},
|
|
|
|
getMode: function() {
|
|
return scope.submittedMode;
|
|
},
|
|
|
|
submit: function(noZoom) {
|
|
scope.route(false, noZoom);
|
|
},
|
|
|
|
destroy: function() {
|
|
scope.reset();
|
|
el.remove();
|
|
scope.$destroy();
|
|
}
|
|
};
|
|
routeUi.hide();
|
|
return routeUi;
|
|
};
|
|
});
|