@fleetbase/leaflet-routing-machine
Version:
ESM module Routing for Leaflet
237 lines (198 loc) • 7.78 kB
JavaScript
import Formatter from './formatter';
import ItineraryBuilder from './itinerary-builder';
export default L.Control.extend({
includes: (typeof L.Evented !== 'undefined' && L.Evented.prototype) || L.Mixin.Events,
options: {
pointMarkerStyle: {
radius: 5,
color: '#03f',
fillColor: 'white',
opacity: 1,
fillOpacity: 0.7,
},
summaryTemplate: '<h2>{name}</h2><h3>{distance}, {time}</h3>',
timeTemplate: '{time}',
containerClassName: '',
alternativeClassName: '',
minimizedClassName: '',
itineraryClassName: '',
totalDistanceRoundingSensitivity: -1,
show: true,
collapsible: undefined,
collapseBtn: function (itinerary) {
var collapseBtn = L.DomUtil.create('span', itinerary.options.collapseBtnClass);
L.DomEvent.on(collapseBtn, 'click', itinerary._toggle, itinerary);
itinerary._container.insertBefore(collapseBtn, itinerary._container.firstChild);
},
collapseBtnClass: 'leaflet-routing-collapse-btn',
},
initialize: function (options) {
L.setOptions(this, options);
this._formatter = this.options.formatter || new Formatter(this.options);
this._itineraryBuilder =
this.options.itineraryBuilder ||
new ItineraryBuilder({
containerClassName: this.options.itineraryClassName,
});
},
onAdd: function (map) {
var collapsible = this.options.collapsible;
collapsible = collapsible || (collapsible === undefined && map.getSize().x <= 640);
this._container = L.DomUtil.create(
'div',
'leaflet-routing-container leaflet-bar ' +
(!this.options.show ? 'leaflet-routing-container-hide ' : '') +
(collapsible ? 'leaflet-routing-collapsible ' : '') +
this.options.containerClassName
);
this._altContainer = this.createAlternativesContainer();
this._container.appendChild(this._altContainer);
L.DomEvent.disableClickPropagation(this._container);
L.DomEvent.addListener(this._container, 'mousewheel', function (e) {
L.DomEvent.stopPropagation(e);
});
if (collapsible) {
this.options.collapseBtn(this);
}
return this._container;
},
onRemove: function () {},
createAlternativesContainer: function () {
return L.DomUtil.create('div', 'leaflet-routing-alternatives-container');
},
setAlternatives: function (routes) {
var i, alt, altDiv;
this._clearAlts();
this._routes = routes;
for (i = 0; i < this._routes.length; i++) {
alt = this._routes[i];
altDiv = this._createAlternative(alt, i);
this._altContainer.appendChild(altDiv);
this._altElements.push(altDiv);
}
this._selectRoute({ route: this._routes[0], alternatives: this._routes.slice(1) });
return this;
},
show: function () {
L.DomUtil.removeClass(this._container, 'leaflet-routing-container-hide');
},
hide: function () {
L.DomUtil.addClass(this._container, 'leaflet-routing-container-hide');
},
_toggle: function () {
var collapsed = L.DomUtil.hasClass(this._container, 'leaflet-routing-container-hide');
this[collapsed ? 'show' : 'hide']();
},
_createAlternative: function (alt, i) {
var altDiv = L.DomUtil.create('div', 'leaflet-routing-alt ' + this.options.alternativeClassName + (i > 0 ? ' leaflet-routing-alt-minimized ' + this.options.minimizedClassName : '')),
template = this.options.summaryTemplate,
data = L.extend(
{
name: alt.name,
distance: this._formatter.formatDistance(alt.summary.totalDistance, this.options.totalDistanceRoundingSensitivity),
time: this._formatter.formatTime(alt.summary.totalTime),
},
alt
);
altDiv.innerHTML = typeof template === 'function' ? template(data) : L.Util.template(template, data);
L.DomEvent.addListener(altDiv, 'click', this._onAltClicked, this);
this.on('routeselected', this._selectAlt, this);
altDiv.appendChild(this._createItineraryContainer(alt));
return altDiv;
},
_clearAlts: function () {
var el = this._altContainer;
while (el && el.firstChild) {
el.removeChild(el.firstChild);
}
this._altElements = [];
},
_createItineraryContainer: function (r) {
var container = this._itineraryBuilder.createContainer(),
steps = this._itineraryBuilder.createStepsContainer(),
i,
instr,
step,
distance,
text,
icon;
container.appendChild(steps);
for (i = 0; i < r.instructions.length; i++) {
instr = r.instructions[i];
text = this._formatter.formatInstruction(instr, i);
distance = this._formatter.formatDistance(instr.distance);
icon = this._formatter.getIconName(instr, i);
step = this._itineraryBuilder.createStep(text, distance, icon, steps);
if (instr.index) {
this._addRowListeners(step, r.coordinates[instr.index]);
}
}
return container;
},
_addRowListeners: function (row, coordinate) {
L.DomEvent.addListener(
row,
'mouseover',
function () {
this._marker = L.circleMarker(coordinate, this.options.pointMarkerStyle).addTo(this._map);
},
this
);
L.DomEvent.addListener(
row,
'mouseout',
function () {
if (this._marker) {
this._map.removeLayer(this._marker);
delete this._marker;
}
},
this
);
L.DomEvent.addListener(
row,
'click',
function (e) {
this._map.panTo(coordinate);
L.DomEvent.stopPropagation(e);
},
this
);
},
_onAltClicked: function (e) {
var altElem = e.target || window.event.srcElement;
while (!L.DomUtil.hasClass(altElem, 'leaflet-routing-alt')) {
altElem = altElem.parentElement;
}
var j = this._altElements.indexOf(altElem);
var alts = this._routes.slice();
var route = alts.splice(j, 1)[0];
this.fire('routeselected', {
route: route,
alternatives: alts,
});
},
_selectAlt: function (e) {
var altElem, j, n, classFn;
altElem = this._altElements[e.route.routesIndex];
if (L.DomUtil.hasClass(altElem, 'leaflet-routing-alt-minimized')) {
for (j = 0; j < this._altElements.length; j++) {
n = this._altElements[j];
classFn = j === e.route.routesIndex ? 'removeClass' : 'addClass';
L.DomUtil[classFn](n, 'leaflet-routing-alt-minimized');
if (this.options.minimizedClassName) {
L.DomUtil[classFn](n, this.options.minimizedClassName);
}
if (j !== e.route.routesIndex) n.scrollTop = 0;
}
}
L.DomEvent.stop(e);
},
_selectRoute: function (routes) {
if (this._marker) {
this._map.removeLayer(this._marker);
delete this._marker;
}
this.fire('routeselected', routes);
},
});