' +
12 | error.message + '
= 1000) {
38 | data = {
39 | value: round(d / 1609.344, sensitivity),
40 | unit: un.miles
41 | };
42 | } else {
43 | data = {
44 | value: round(yards, sensitivity),
45 | unit: un.yards
46 | };
47 | }
48 | } else {
49 | v = round(d, sensitivity);
50 | data = {
51 | value: v >= 1000 ? (v / 1000) : v,
52 | unit: v >= 1000 ? un.kilometers : un.meters
53 | };
54 | }
55 |
56 | if (simpleRounding) {
57 | data.value = data.value.toFixed(-sensitivity);
58 | }
59 |
60 | return L.Util.template(this.options.distanceTemplate, data);
61 | },
62 |
63 | _round: function(d, sensitivity) {
64 | var s = sensitivity || this.options.roundingSensitivity,
65 | pow10 = Math.pow(10, (Math.floor(d / s) + '').length - 1),
66 | r = Math.floor(d / pow10),
67 | p = (r > 5) ? pow10 : pow10 / 2;
68 |
69 | return Math.round(d / p) * p;
70 | },
71 |
72 | formatTime: function(t /* Number (seconds) */) {
73 | var un = this.options.unitNames || this._localization.localize('units');
74 | // More than 30 seconds precision looks ridiculous
75 | t = Math.round(t / 30) * 30;
76 |
77 | if (t > 86400) {
78 | return Math.round(t / 3600) + ' ' + un.hours;
79 | } else if (t > 3600) {
80 | return Math.floor(t / 3600) + ' ' + un.hours + ' ' +
81 | Math.round((t % 3600) / 60) + ' ' + un.minutes;
82 | } else if (t > 300) {
83 | return Math.round(t / 60) + ' ' + un.minutes;
84 | } else if (t > 60) {
85 | return Math.floor(t / 60) + ' ' + un.minutes +
86 | (t % 60 !== 0 ? ' ' + (t % 60) + ' ' + un.seconds : '');
87 | } else {
88 | return t + ' ' + un.seconds;
89 | }
90 | },
91 |
92 | formatInstruction: function(instr, i) {
93 | if (instr.text === undefined) {
94 | return this.capitalize(L.Util.template(this._getInstructionTemplate(instr, i),
95 | L.extend({}, instr, {
96 | exitStr: instr.exit ? this._localization.localize('formatOrder')(instr.exit) : '',
97 | dir: this._localization.localize(['directions', instr.direction]),
98 | modifier: this._localization.localize(['directions', instr.modifier])
99 | })));
100 | } else {
101 | return instr.text;
102 | }
103 | },
104 |
105 | getIconName: function(instr, i) {
106 | switch (instr.type) {
107 | case 'Head':
108 | if (i === 0) {
109 | return 'depart';
110 | }
111 | break;
112 | case 'WaypointReached':
113 | return 'via';
114 | case 'Roundabout':
115 | return 'enter-roundabout';
116 | case 'DestinationReached':
117 | return 'arrive';
118 | }
119 |
120 | switch (instr.modifier) {
121 | case 'Straight':
122 | return 'continue';
123 | case 'SlightRight':
124 | return 'bear-right';
125 | case 'Right':
126 | return 'turn-right';
127 | case 'SharpRight':
128 | return 'sharp-right';
129 | case 'TurnAround':
130 | case 'Uturn':
131 | return 'u-turn';
132 | case 'SharpLeft':
133 | return 'sharp-left';
134 | case 'Left':
135 | return 'turn-left';
136 | case 'SlightLeft':
137 | return 'bear-left';
138 | }
139 | },
140 |
141 | capitalize: function(s) {
142 | return s.charAt(0).toUpperCase() + s.substring(1);
143 | },
144 |
145 | _getInstructionTemplate: function(instr, i) {
146 | var type = instr.type === 'Straight' ? (i === 0 ? 'Head' : 'Continue') : instr.type,
147 | strings = this._localization.localize(['instructions', type]);
148 |
149 | if (!strings) {
150 | strings = [
151 | this._localization.localize(['directions', type]),
152 | ' ' + this._localization.localize(['instructions', 'Onto'])
153 | ];
154 | }
155 |
156 | return strings[0] + (strings.length > 1 && instr.road ? strings[1] : '');
157 | }
158 | });
159 | })();
160 |
--------------------------------------------------------------------------------
/src/geocoder-element.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | 'use strict';
3 |
4 | var L = require('leaflet');
5 | var Autocomplete = require('./autocomplete');
6 | var Localization = require('./localization');
7 |
8 | function selectInputText(input) {
9 | if (input.setSelectionRange) {
10 | // On iOS, select() doesn't work
11 | input.setSelectionRange(0, 9999);
12 | } else {
13 | // On at least IE8, setSeleectionRange doesn't exist
14 | input.select();
15 | }
16 | }
17 |
18 | module.exports = L.Class.extend({
19 | includes: ((typeof L.Evented !== 'undefined' && L.Evented.prototype) || L.Mixin.Events),
20 |
21 | options: {
22 | createGeocoder: function(i, nWps, options) {
23 | var container = L.DomUtil.create('div', 'leaflet-routing-geocoder'),
24 | input = L.DomUtil.create('input', '', container),
25 | remove = options.addWaypoints ? L.DomUtil.create('span', 'leaflet-routing-remove-waypoint', container) : undefined;
26 |
27 | input.disabled = !options.addWaypoints;
28 |
29 | return {
30 | container: container,
31 | input: input,
32 | closeButton: remove
33 | };
34 | },
35 | geocoderPlaceholder: function(i, numberWaypoints, geocoderElement) {
36 | var l = new Localization(geocoderElement.options.language).localize('ui');
37 | return i === 0 ?
38 | l.startPlaceholder :
39 | (i < numberWaypoints - 1 ?
40 | L.Util.template(l.viaPlaceholder, {viaNumber: i}) :
41 | l.endPlaceholder);
42 | },
43 |
44 | geocoderClass: function() {
45 | return '';
46 | },
47 |
48 | waypointNameFallback: function(latLng) {
49 | var ns = latLng.lat < 0 ? 'S' : 'N',
50 | ew = latLng.lng < 0 ? 'W' : 'E',
51 | lat = (Math.round(Math.abs(latLng.lat) * 10000) / 10000).toString(),
52 | lng = (Math.round(Math.abs(latLng.lng) * 10000) / 10000).toString();
53 | return ns + lat + ', ' + ew + lng;
54 | },
55 | maxGeocoderTolerance: 200,
56 | autocompleteOptions: {},
57 | language: 'en',
58 | },
59 |
60 | initialize: function(wp, i, nWps, options) {
61 | L.setOptions(this, options);
62 |
63 | var g = this.options.createGeocoder(i, nWps, this.options),
64 | closeButton = g.closeButton,
65 | geocoderInput = g.input;
66 | geocoderInput.setAttribute('placeholder', this.options.geocoderPlaceholder(i, nWps, this));
67 | geocoderInput.className = this.options.geocoderClass(i, nWps);
68 |
69 | this._element = g;
70 | this._waypoint = wp;
71 |
72 | this.update();
73 | // This has to be here, or geocoder's value will not be properly
74 | // initialized.
75 | // TODO: look into why and make _updateWaypointName fix this.
76 | geocoderInput.value = wp.name;
77 |
78 | L.DomEvent.addListener(geocoderInput, 'click', function() {
79 | selectInputText(this);
80 | }, geocoderInput);
81 |
82 | if (closeButton) {
83 | L.DomEvent.addListener(closeButton, 'click', function() {
84 | this.fire('delete', { waypoint: this._waypoint });
85 | }, this);
86 | }
87 |
88 | if (typeof this.options.formatGeocoderResult == 'function') {
89 | this.options.autocompleteOptions.formatGeocoderResult = this.options.formatGeocoderResult;
90 | }
91 |
92 | new Autocomplete(geocoderInput, function(r) {
93 | geocoderInput.value = r.name;
94 | wp.name = r.name;
95 | wp.latLng = r.center;
96 | this.fire('geocoded', { waypoint: wp, value: r });
97 | }, this, L.extend({
98 | resultFn: this.options.geocoder.geocode,
99 | resultContext: this.options.geocoder,
100 | autocompleteFn: this.options.geocoder.suggest,
101 | autocompleteContext: this.options.geocoder
102 | }, this.options.autocompleteOptions));
103 | },
104 |
105 | getContainer: function() {
106 | return this._element.container;
107 | },
108 |
109 | setValue: function(v) {
110 | this._element.input.value = v;
111 | },
112 |
113 | update: function(force) {
114 | var wp = this._waypoint,
115 | wpCoords;
116 |
117 | wp.name = wp.name || '';
118 |
119 | if (wp.latLng && (force || !wp.name)) {
120 | wpCoords = this.options.waypointNameFallback(wp.latLng);
121 | if (this.options.geocoder && this.options.geocoder.reverse) {
122 | this.options.geocoder.reverse(wp.latLng, 67108864 /* zoom 18 */, function(rs) {
123 | if (rs.length > 0 && rs[0].center.distanceTo(wp.latLng) < this.options.maxGeocoderTolerance) {
124 | wp.name = rs[0].name;
125 | } else {
126 | wp.name = wpCoords;
127 | }
128 | this._update();
129 | }, this);
130 | } else {
131 | wp.name = wpCoords;
132 | this._update();
133 | }
134 | }
135 | },
136 |
137 | focus: function() {
138 | var input = this._element.input;
139 | input.focus();
140 | selectInputText(input);
141 | },
142 |
143 | _update: function() {
144 | var wp = this._waypoint,
145 | value = wp && wp.name ? wp.name : '';
146 | this.setValue(value);
147 | this.fire('reversegeocoded', {waypoint: wp, value: value});
148 | }
149 | });
150 | })();
151 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | var L = require('leaflet'),
2 | Control = require('./control'),
3 | Itinerary = require('./itinerary'),
4 | Line = require('./line'),
5 | OSRMv1 = require('./osrm-v1'),
6 | Plan = require('./plan'),
7 | Waypoint = require('./waypoint'),
8 | Autocomplete = require('./autocomplete'),
9 | Formatter = require('./formatter'),
10 | GeocoderElement = require('./geocoder-element'),
11 | Localization = require('./localization'),
12 | ItineraryBuilder = require('./itinerary-builder'),
13 | Mapbox = require('./mapbox'),
14 | ErrorControl = require('./error-control');
15 |
16 | L.routing = {
17 | control: function(options) { return new Control(options); },
18 | itinerary: function(options) {
19 | return Itinerary(options);
20 | },
21 | line: function(route, options) {
22 | return new Line(route, options);
23 | },
24 | plan: function(waypoints, options) {
25 | return new Plan(waypoints, options);
26 | },
27 | waypoint: function(latLng, name, options) {
28 | return new Waypoint(latLng, name, options);
29 | },
30 | osrmv1: function(options) {
31 | return new OSRMv1(options);
32 | },
33 | localization: function(options) {
34 | return new Localization(options);
35 | },
36 | formatter: function(options) {
37 | return new Formatter(options);
38 | },
39 | geocoderElement: function(wp, i, nWps, plan) {
40 | return new L.Routing.GeocoderElement(wp, i, nWps, plan);
41 | },
42 | itineraryBuilder: function(options) {
43 | return new ItineraryBuilder(options);
44 | },
45 | mapbox: function(accessToken, options) {
46 | return new Mapbox(accessToken, options);
47 | },
48 | errorControl: function(routingControl, options) {
49 | return new ErrorControl(routingControl, options);
50 | },
51 | autocomplete: function(elem, callback, context, options) {
52 | return new Autocomplete(elem, callback, context, options);
53 | }
54 | };
55 |
56 | module.exports = L.Routing = {
57 | Control: Control,
58 | Itinerary: Itinerary,
59 | Line: Line,
60 | OSRMv1: OSRMv1,
61 | Plan: Plan,
62 | Waypoint: Waypoint,
63 | Autocomplete: Autocomplete,
64 | Formatter: Formatter,
65 | GeocoderElement: GeocoderElement,
66 | Localization: Localization,
67 | ItineraryBuilder: ItineraryBuilder,
68 |
69 | // Legacy; remove these in next major release
70 | control: L.routing.control,
71 | itinerary: L.routing.itinerary,
72 | line: L.routing.line,
73 | plan: L.routing.plan,
74 | waypoint: L.routing.waypoint,
75 | osrmv1: L.routing.osrmv1,
76 | geocoderElement: L.routing.geocoderElement,
77 | mapbox: L.routing.mapbox,
78 | errorControl: L.routing.errorControl,
79 | };
80 |
--------------------------------------------------------------------------------
/src/itinerary-builder.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | 'use strict';
3 |
4 | var L = require('leaflet');
5 |
6 | module.exports = L.Class.extend({
7 | options: {
8 | containerClassName: ''
9 | },
10 |
11 | initialize: function(options) {
12 | L.setOptions(this, options);
13 | },
14 |
15 | createContainer: function(className) {
16 | var table = L.DomUtil.create('table', (className || '') + ' ' + this.options.containerClassName),
17 | colgroup = L.DomUtil.create('colgroup', '', table);
18 |
19 | L.DomUtil.create('col', 'leaflet-routing-instruction-icon', colgroup);
20 | L.DomUtil.create('col', 'leaflet-routing-instruction-text', colgroup);
21 | L.DomUtil.create('col', 'leaflet-routing-instruction-distance', colgroup);
22 |
23 | return table;
24 | },
25 |
26 | createStepsContainer: function() {
27 | return L.DomUtil.create('tbody', '');
28 | },
29 |
30 | createStep: function(text, distance, icon, steps) {
31 | var row = L.DomUtil.create('tr', '', steps),
32 | span,
33 | td;
34 | td = L.DomUtil.create('td', '', row);
35 | span = L.DomUtil.create('span', 'leaflet-routing-icon leaflet-routing-icon-'+icon, td);
36 | td.appendChild(span);
37 | td = L.DomUtil.create('td', '', row);
38 | td.appendChild(document.createTextNode(text));
39 | td = L.DomUtil.create('td', '', row);
40 | td.appendChild(document.createTextNode(distance));
41 | return row;
42 | }
43 | });
44 | })();
45 |
--------------------------------------------------------------------------------
/src/itinerary.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | 'use strict';
3 |
4 | var L = require('leaflet');
5 | var Formatter = require('./formatter');
6 | var ItineraryBuilder = require('./itinerary-builder');
7 |
8 | module.exports = L.Control.extend({
9 | includes: ((typeof L.Evented !== 'undefined' && L.Evented.prototype) || L.Mixin.Events),
10 |
11 | options: {
12 | pointMarkerStyle: {
13 | radius: 5,
14 | color: '#03f',
15 | fillColor: 'white',
16 | opacity: 1,
17 | fillOpacity: 0.7
18 | },
19 | summaryTemplate: '