diff --git a/dist/mapbox-gl-directions.css b/dist/mapbox-gl-directions.css index 075e850..9fb1850 100644 --- a/dist/mapbox-gl-directions.css +++ b/dist/mapbox-gl-directions.css @@ -30,6 +30,7 @@ } .directions-control.directions-control-directions { background:rgba(0,0,0,0.75); + color:#fff; top:0; right:0; bottom:0; @@ -222,6 +223,11 @@ vertical-align:top; } +.mapbox-directions-error { + padding:20px; + font-size:20px; + line-height:25px; + } .mapbox-directions-steps { position:relative; list-style:none; @@ -321,8 +327,7 @@ .mapbox-directions-profile { margin:5px 10px; } /* Instructions container */ -.directions-control.directions-control-directions { top:60%; } - +.directions-control.directions-control-directions { top:auto; max-height:40%; } } @-webkit-keyframes rotate { from { -webkit-transform: rotate(0deg); } to { -webkit-transform: rotate(360deg); } } diff --git a/example/index.js b/example/index.js index dd978ea..5c517d6 100644 --- a/example/index.js +++ b/example/index.js @@ -12,8 +12,7 @@ var map = new mapboxgl.Map({ var directions = mapboxgl.Directions({ unit: 'metric', profile: 'walking', - container: 'directions', - proximity: [-79.45, 43.65] + container: 'directions' }); var button = document.createElement('button'); @@ -25,7 +24,7 @@ map.addControl(directions); map.on('load', () => { button.addEventListener('click', function() { - directions.setOrigin('Toronto'); - directions.setDestination([-78, 42]); + directions.setOrigin('Montreal Quebec'); + directions.setDestination('Toledo Spain'); }); }); diff --git a/src/actions/index.js b/src/actions/index.js index ba1797d..ac77494 100644 --- a/src/actions/index.js +++ b/src/actions/index.js @@ -83,6 +83,8 @@ function geocode(query, callback) { return mapbox.geocodeForward(query.trim(), options, (err, res) => { if (err) throw err; + if (res.error) return dispatch(setError(res.error)); + dispatch(setError(null)); return dispatch(callback(res.features)); }); }; @@ -96,7 +98,8 @@ function fetchDirections(query, profile) { geometry: 'polyline' }, (err, res) => { if (err) throw err; - if (res.error) throw res.error; + if (res.error) return dispatch(setError(res.error)); + dispatch(setError(null)); if (!res.routes[routeIndex]) dispatch(setRouteIndex(0)); dispatch(setDirections(res.routes)); @@ -160,12 +163,23 @@ function setLoading(input, loading) { }; } +function setError(error) { + return dispatch => { + dispatch({ + type: 'ERROR', + error + }); + if (error) dispatch(eventEmit('directions.error', { error: error })); + }; +} + export function clearOrigin() { return dispatch => { dispatch({ type: types.ORIGIN_CLEAR }); dispatch(eventEmit('directions.clear', { type: 'origin' })); + dispatch(setError(null)); }; } @@ -175,6 +189,7 @@ export function clearDestination() { type: types.DESTINATION_CLEAR }); dispatch(eventEmit('directions.clear', { type: 'destination' })); + dispatch(setError(null)); }; } diff --git a/src/constants/action_types.js b/src/constants/action_types.js index cf0386b..ff51184 100644 --- a/src/constants/action_types.js +++ b/src/constants/action_types.js @@ -5,6 +5,7 @@ export const DESTINATION_LOADING = 'DESTINATION_LOADING'; export const DIRECTIONS = 'DIRECTIONS'; export const DIRECTIONS_PROFILE = 'DIRECTIONS_PROFILE'; export const EVENTS = 'EVENTS'; +export const ERROR = 'ERROR'; export const HOVER_MARKER = 'HOVER_MARKER'; export const ORIGIN = 'ORIGIN'; export const ORIGIN_CLEAR = 'ORIGIN_CLEAR'; diff --git a/src/controls/instructions.js b/src/controls/instructions.js index 53a92c2..646b986 100644 --- a/src/controls/instructions.js +++ b/src/controls/instructions.js @@ -3,7 +3,8 @@ import template from 'lodash.template'; import isEqual from 'lodash.isequal'; let fs = require('fs'); // substack/brfs#39 -let tmpl = template(fs.readFileSync(__dirname + '/../templates/instructions.html', 'utf8')); +let instructionsTemplate = template(fs.readFileSync(__dirname + '/../templates/instructions.html', 'utf8')); +let errorTemplate = template(fs.readFileSync(__dirname + '/../templates/error.html', 'utf8')); /** * Summary/Instructions controller @@ -27,13 +28,18 @@ export default class Instructions { render() { this.store.subscribe(() => { const { hoverMarker } = this.actions; - const { routeIndex, unit, directions } = this.store.getState(); + const { routeIndex, unit, directions, error } = this.store.getState(); const shouldRender = !isEqual(directions[routeIndex], this.directions); + if (error) { + this.container.innerHTML = errorTemplate({ error }); + return; + } + if (directions.length && shouldRender) { const direction = this.directions = directions[routeIndex]; - this.container.innerHTML = tmpl({ + this.container.innerHTML = instructionsTemplate({ routeIndex, steps: direction.steps, format: format[unit], diff --git a/src/directions.js b/src/directions.js index e5667ce..95207b9 100644 --- a/src/directions.js +++ b/src/directions.js @@ -401,6 +401,7 @@ export default class Directions extends mapboxgl.Control { * - __directions.origin__ `{ feature } Fired when origin is set` * - __directions.destination__ `{ feature } Fired when destination is set` * - __directions.route__ `{ route } Fired when a route is updated` + * - __directions.error__ `{ error } Error as string * @param {Function} fn function that's called when the event is emitted. * @returns {Directions} this; */ diff --git a/src/reducers/index.js b/src/reducers/index.js index c44ec5f..1831c4e 100644 --- a/src/reducers/index.js +++ b/src/reducers/index.js @@ -123,6 +123,11 @@ function data(state = initialState, action) { routeIndex: action.routeIndex }); + case types.ERROR: + return Object.assign({}, state, { + error: action.error + }); + default: return state; } diff --git a/src/templates/error.html b/src/templates/error.html new file mode 100644 index 0000000..030a748 --- /dev/null +++ b/src/templates/error.html @@ -0,0 +1,5 @@ +