UNPKG

@fleetbase/leaflet-routing-machine

Version:
378 lines (325 loc) 11.7 kB
import Itinerary from './itinerary'; import Line from './line'; import Plan from './plan'; import OSRMv1 from './osrm-v1'; export default Itinerary.extend({ options: { fitSelectedRoutes: 'smart', routeLine: function (route, options) { return new Line(route, options); }, autoRoute: true, routeWhileDragging: false, routeDragInterval: 500, waypointMode: 'connect', showAlternatives: false, markerOptions: {}, defaultErrorHandler: function (e) { console.error('Routing error:', e.error); }, }, initialize: function (options) { L.Util.setOptions(this, options); this._router = this.options.router || new OSRMv1(options); this._plan = this.options.plan || new Plan(this.options.waypoints, options); this._requestCount = 0; Itinerary.prototype.initialize.call(this, options); this.on('routeselected', this._routeSelected, this); if (this.options.defaultErrorHandler) { this.on('routingerror', this.options.defaultErrorHandler); } this._plan.on('waypointschanged', this._onWaypointsChanged, this); if (options.routeWhileDragging) { this._setupRouteDragging(); } }, _onZoomEnd: function () { if (!this._selectedRoute || !this._router.requiresMoreDetail) { return; } var map = this._map; if (this._router.requiresMoreDetail(this._selectedRoute, map.getZoom(), map.getBounds())) { this.route({ callback: L.bind(function (err, routes) { var i; if (!err) { for (i = 0; i < routes.length; i++) { this._routes[i].properties = routes[i].properties; } this._updateLineCallback(err, routes); } }, this), simplifyGeometry: false, geometryOnly: true, }); } }, onAdd: function (map) { if (this.options.autoRoute) { this.route(); } var container = Itinerary.prototype.onAdd.call(this, map); this._map = map; this._map.addLayer(this._plan); this._map.on('zoomend', this._onZoomEnd, this); if (this._plan.options.geocoder) { container.insertBefore(this._plan.createGeocoders(), container.firstChild); } return container; }, onRemove: function (map) { map.off('zoomend', this._onZoomEnd, this); if (this._line) { map.removeLayer(this._line); } map.removeLayer(this._plan); if (this._alternatives && this._alternatives.length > 0) { for (var i = 0, len = this._alternatives.length; i < len; i++) { map.removeLayer(this._alternatives[i]); } } return Itinerary.prototype.onRemove.call(this, map); }, getWaypoints: function () { return this._plan.getWaypoints(); }, setWaypoints: function (waypoints) { this._plan.setWaypoints(waypoints); return this; }, spliceWaypoints: function () { var removed = this._plan.spliceWaypoints.apply(this._plan, arguments); return removed; }, getPlan: function () { return this._plan; }, getRouter: function () { return this._router; }, _routeSelected: function (e) { var route = (this._selectedRoute = e.route), alternatives = this.options.showAlternatives && e.alternatives, fitMode = this.options.fitSelectedRoutes, fitBounds = (fitMode === 'smart' && !this._waypointsVisible()) || (fitMode !== 'smart' && fitMode); this._updateLines({ route: route, alternatives: alternatives }); if (fitBounds) { this._map.fitBounds(this._line.getBounds()); } if (this.options.waypointMode === 'snap') { this._plan.off('waypointschanged', this._onWaypointsChanged, this); this.setWaypoints(route.waypoints); this._plan.on('waypointschanged', this._onWaypointsChanged, this); } }, _waypointsVisible: function () { var wps = this.getWaypoints(), mapSize, bounds, boundsSize, i, p; try { mapSize = this._map.getSize(); for (i = 0; i < wps.length; i++) { p = this._map.latLngToLayerPoint(wps[i].latLng); if (bounds) { bounds.extend(p); } else { bounds = L.bounds([p]); } } boundsSize = bounds.getSize(); return (boundsSize.x > mapSize.x / 5 || boundsSize.y > mapSize.y / 5) && this._waypointsInViewport(); } catch (e) { return false; } }, _waypointsInViewport: function () { var wps = this.getWaypoints(), mapBounds, i; try { mapBounds = this._map.getBounds(); } catch (e) { return false; } for (i = 0; i < wps.length; i++) { if (mapBounds.contains(wps[i].latLng)) { return true; } } return false; }, _updateLines: function (routes) { var addWaypoints = this.options.addWaypoints !== undefined ? this.options.addWaypoints : true; this._clearLines(); // add alternatives first so they lie below the main route this._alternatives = []; if (routes.alternatives) routes.alternatives.forEach(function (alt, i) { this._alternatives[i] = this.options.routeLine( alt, L.extend( { isAlternative: true, }, this.options.altLineOptions || this.options.lineOptions ) ); this._alternatives[i].addTo(this._map); this._hookAltEvents(this._alternatives[i]); }, this); this._line = this.options.routeLine( routes.route, L.extend( { addWaypoints: addWaypoints, extendToWaypoints: this.options.waypointMode === 'connect', }, this.options.lineOptions ) ); this._line.addTo(this._map); this._hookEvents(this._line); }, _hookEvents: function (l) { l.on( 'linetouched', function (e) { if (e.afterIndex < this.getWaypoints().length - 1) { this._plan.dragNewWaypoint(e); } }, this ); }, _hookAltEvents: function (l) { l.on( 'linetouched', function (e) { var alts = this._routes.slice(); var selected = alts.splice(e.target._route.routesIndex, 1)[0]; this.fire('routeselected', { route: selected, alternatives: alts }); }, this ); }, _onWaypointsChanged: function (e) { if (this.options.autoRoute) { this.route({}); } if (!this._plan.isReady()) { this._clearLines(); this._clearAlts(); } this.fire('waypointschanged', { waypoints: e.waypoints }); }, _setupRouteDragging: function () { var timer = 0, waypoints; this._plan.on( 'waypointdrag', L.bind(function (e) { waypoints = e.waypoints; if (!timer) { timer = setTimeout( L.bind(function () { this.route({ waypoints: waypoints, geometryOnly: true, callback: L.bind(this._updateLineCallback, this), }); timer = undefined; }, this), this.options.routeDragInterval ); } }, this) ); this._plan.on( 'waypointdragend', function () { if (timer) { clearTimeout(timer); timer = undefined; } this.route(); }, this ); }, _updateLineCallback: function (err, routes) { if (!err) { routes = routes.slice(); var selected = routes.splice(this._selectedRoute.routesIndex, 1)[0]; this._updateLines({ route: selected, alternatives: this.options.showAlternatives ? routes : [], }); } else if (err.type !== 'abort') { this._clearLines(); } }, route: function (options) { var ts = ++this._requestCount, wps; if (this._pendingRequest && this._pendingRequest.abort) { this._pendingRequest.abort(); this._pendingRequest = null; } options = options || {}; if (this._plan.isReady()) { if (this.options.useZoomParameter) { options.z = this._map && this._map.getZoom(); } wps = (options && options.waypoints) || this._plan.getWaypoints(); this.fire('routingstart', { waypoints: wps }); this._pendingRequest = this._router.route( wps, function (err, routes) { this._pendingRequest = null; if (options.callback) { return options.callback.call(this, err, routes); } // Prevent race among multiple requests, // by checking the current request's count // against the last request's; ignore result if // this isn't the last request. if (ts === this._requestCount) { this._clearLines(); this._clearAlts(); if (err && err.type !== 'abort') { this.fire('routingerror', { error: err }); return; } routes.forEach(function (route, i) { route.routesIndex = i; }); if (!options.geometryOnly) { this.fire('routesfound', { waypoints: wps, routes: routes }); this.setAlternatives(routes); } else { var selectedRoute = routes.splice(0, 1)[0]; this._routeSelected({ route: selectedRoute, alternatives: routes }); } } }, this, options ); } }, _clearLines: function () { if (this._line) { this._map.removeLayer(this._line); delete this._line; } if (this._alternatives && this._alternatives.length) { for (var i in this._alternatives) { this._map.removeLayer(this._alternatives[i]); } this._alternatives = []; } }, });