diff --git a/.gitignore b/.gitignore index 4f19409..09b5414 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ env.test.sh node_modules/ +dist/ \ No newline at end of file diff --git a/API.md b/API.md index 83635fe..c8226d3 100644 --- a/API.md +++ b/API.md @@ -1,6 +1,6 @@ -# mapboxgl.Directions +# MapboxDirections -A directions component using Mapbox Directions APi +A directions component using Mapbox Directions API **Parameters** @@ -10,7 +10,6 @@ A directions component using Mapbox Directions APi - `options.interactive` **\[[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)]** Enable/Disable mouse or touch interactivity from the plugin (optional, default `true`) - `options.profile` **\[[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)]** Routing profile to use. Options: `driving`, `walking`, `cycling` (optional, default `"driving"`) - `options.unit` **\[[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)]** Measurement system to be used in navigation instructions. Options: `imperial`, `metric` (optional, default `"imperial"`) - - `options.container` **([string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String) \| [Element](https://developer.mozilla.org/en-US/docs/Web/API/Element))** HTML element to initialize the map in (or element id as string). If no container is passed map.getContainer() is used instead. - `options.geocoder` **\[[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)]** Pass options available to mapbox-gl-geocoder as [documented here](https://github.com/mapbox/mapbox-gl-geocoder/blob/master/API.md#mapboxglgeocoder). - `options.controls` **\[[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)]** - `options.controls.inputs` **\[[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)]** Hide or display the inputs control. (optional, default `true`) @@ -19,18 +18,30 @@ A directions component using Mapbox Directions APi **Examples** ```javascript -var directions = new mapboxgl.Directions({ - container: 'directions', +var MapboxDirections = require('../src/index'); +var directions = new MapboxDirections({ + accessToken: 'YOUR-MAPBOX-ACCESS-TOKEN', unit: 'metric', - profile: 'walking' + profile: 'cycling' }); - +// add to your mapboxgl map map.addControl(directions); ``` -Returns **Directions** `this` +Returns **[MapboxDirections](#mapboxdirections)** `this` + +## onRemove + +Removes the control from the map it has been added to. This is called by `map.removeControl`, +which is the recommended method to remove controls. + +**Parameters** + +- `map` -# interactive +Returns **Control** `this` + +## interactive Turn on or off interactivity @@ -38,15 +49,15 @@ Turn on or off interactivity - `state` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** sets interactivity based on a state of `true` or `false`. -Returns **Directions** this +Returns **[MapboxDirections](#mapboxdirections)** this -# getOrigin +## getOrigin Returns the origin of the current route. Returns **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** origin -# setOrigin +## setOrigin Sets origin. _Note:_ calling this method requires the [map load event](https://www.mapbox.com/mapbox-gl-js/api/#Map.load) to have run. @@ -55,15 +66,15 @@ to have run. - `query` **([Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)<[number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)> | [String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String))** An array of coordinates [lng, lat] or location name as a string. -Returns **Directions** this +Returns **[MapboxDirections](#mapboxdirections)** this -# getDestination +## getDestination Returns the destination of the current route. Returns **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** destination -# setDestination +## setDestination Sets destination. _Note:_ calling this method requires the [map load event](https://www.mapbox.com/mapbox-gl-js/api/#Map.load) to have run. @@ -72,15 +83,15 @@ to have run. - `query` **([Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)<[number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)> | [String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String))** An array of coordinates [lng, lat] or location name as a string. -Returns **Directions** this +Returns **[MapboxDirections](#mapboxdirections)** this -# reverse +## reverse Swap the origin and destination. -Returns **Directions** this +Returns **[MapboxDirections](#mapboxdirections)** this -# addWaypoint +## addWaypoint Add a waypoint to the route. _Note:_ calling this method requires the [map load event](https://www.mapbox.com/mapbox-gl-js/api/#Map.load) to have run. @@ -90,9 +101,9 @@ Add a waypoint to the route. _Note:_ calling this method requires the - `index` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)** position waypoint should be placed in the waypoint array - `waypoint` **([Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)<[number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)> | Point)** can be a GeoJSON Point Feature or [lng, lat] coordinates. -Returns **Directions** this; +Returns **[MapboxDirections](#mapboxdirections)** this; -# setWaypoint +## setWaypoint Change the waypoint at a given index in the route. _Note:_ calling this method requires the [map load event](https://www.mapbox.com/mapbox-gl-js/api/#Map.load) @@ -103,9 +114,9 @@ to have run. - `index` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)** indexed position of the waypoint to update - `waypoint` **([Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)<[number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)> | Point)** can be a GeoJSON Point Feature or [lng, lat] coordinates. -Returns **Directions** this; +Returns **[MapboxDirections](#mapboxdirections)** this; -# removeWaypoint +## removeWaypoint Remove a waypoint from the route. @@ -113,15 +124,21 @@ Remove a waypoint from the route. - `index` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)** position in the waypoints array. -Returns **Directions** this; +Returns **[MapboxDirections](#mapboxdirections)** this; -# getWaypoints +## getWaypoints Fetch all current waypoints in a route. Returns **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)** waypoints -# on +## removeRoutes + +Removes all routes and waypoints from the map. + +Returns **[MapboxDirections](#mapboxdirections)** this; + +## on Subscribe to events that happen within the plugin. @@ -136,4 +153,67 @@ Subscribe to events that happen within the plugin. - **error** \`{ error } Error as string - `fn` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)** function that's called when the event is emitted. -Returns **Directions** this; +Returns **[MapboxDirections](#mapboxdirections)** this; + +# getResult + +Return the input + +Returns **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** input + +# query + +Set & query the input + +**Parameters** + +- `query` **([Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array) \| [String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String))** An array of coordinates [lng, lat] or location name as a string. + +Returns **Geocoder** this + +# setInput + +Set input + +**Parameters** + +- `value` **([Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array) \| [String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String))** An array of coordinates [lng, lat] or location name as a string. Calling this function just sets the input and does not trigger an API request. + +Returns **Geocoder** this + +# on + +Subscribe to events that happen within the plugin. + +**Parameters** + +- `type` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** name of event. Available events and the data passed into their respective event objects are:- **clear** `Emitted when the input is cleared` + - **loading** `Emitted when the geocoder is looking up a query` + - **results** `{ results } Fired when the geocoder returns a response` + - **result** `{ result } Fired when input is set` + - **error** \`{ error } Error as string +- `fn` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)** function that's called when the event is emitted. + +Returns **Geocoder** this; + +# fire + +Fire an event + +**Parameters** + +- `type` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** event name. +- `data` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** event data to pass to the function subscribed. + +Returns **Geocoder** this + +# off + +Remove an event + +**Parameters** + +- `type` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** Event name. +- `fn` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)** Function that should unsubscribe to the event emitted. + +Returns **Geocoder** this diff --git a/CHANGELOG.md b/CHANGELOG.md index 3515171..551e0a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,17 @@ +## 3.0.0 + +Support for the Mapbox GL JS 0.27.0 API. This is compatible with 0.27.0 and later, and not compatible with earlier versions. + +- [breaking] `container` option removed - attaching the control outside of the map is no longer supported +- [breaking] `position` option removed - the `addControl` method now specifies the position +- [breaking] Now exports `MapboxDirections` rather than attaches to `mapbox.Directions` +- [internal] no longer creates a new map control for each of the two geocoders, instead creates two internal geocoders +- [feature] `removeRoutes` method that removes all route lines, waypoints, and instructions + ## 2.2.0 - [feature] Defer mapboxgl dependency til runtime to support webpack async loading #86 https://github.com/mapbox/mapbox-gl-directions/pull/86 - [bug] Fix mapboxgl.GeoJSONSource deprecation in gl-js v.22 and map.load race condition - ## 2.1.0 - [bug] Warn if mapboxgl is not present [#66](https://github.com/mapbox/mapbox-gl-directions/issues/66) diff --git a/README.md b/README.md index 6cf6731..7886faf 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,25 @@ A full featured directions plugin for [mapbox-gl-js](https://github.com/mapbox/m ### Usage -See https://www.mapbox.com/mapbox-gl-js/example/mapbox-gl-directions/ +```javascript +var mapboxgl = require('mapbox-gl'); +var MapboxDirections = require('mapbox-gl-directions'); + +var directions = new MapboxDirections({ + accessToken: 'YOUR-MAPBOX-ACCESS-TOKEN', + unit: 'metric', + profile: 'cycling' +}); + +var map = new mapboxgl.Map({ + container: 'map', + style: 'mapbox://styles/mapbox/streets-v9' +}); + +map.addControl(directions, 'top-left'); +``` + +Live example: https://www.mapbox.com/mapbox-gl-js/example/mapbox-gl-directions/ ### Deeper dive diff --git a/circle.yml b/circle.yml new file mode 100644 index 0000000..7989a72 --- /dev/null +++ b/circle.yml @@ -0,0 +1,3 @@ +machine: + node: + version: 4 \ No newline at end of file diff --git a/dist/mapbox-gl-directions.js b/dist/mapbox-gl-directions.js deleted file mode 100644 index d2533d1..0000000 --- a/dist/mapbox-gl-directions.js +++ /dev/null @@ -1,7460 +0,0 @@ -(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.mapboxDirections = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 0 && this._events[type].length > m) { - this._events[type].warned = true; - console.error('(node) warning: possible EventEmitter memory ' + - 'leak detected. %d listeners added. ' + - 'Use emitter.setMaxListeners() to increase limit.', - this._events[type].length); - if (typeof console.trace === 'function') { - // not supported in IE 10 - console.trace(); - } - } - } - - return this; -}; - -EventEmitter.prototype.on = EventEmitter.prototype.addListener; - -EventEmitter.prototype.once = function(type, listener) { - if (!isFunction(listener)) - throw TypeError('listener must be a function'); - - var fired = false; - - function g() { - this.removeListener(type, g); - - if (!fired) { - fired = true; - listener.apply(this, arguments); - } - } - - g.listener = listener; - this.on(type, g); - - return this; -}; - -// emits a 'removeListener' event iff the listener was removed -EventEmitter.prototype.removeListener = function(type, listener) { - var list, position, length, i; - - if (!isFunction(listener)) - throw TypeError('listener must be a function'); - - if (!this._events || !this._events[type]) - return this; - - list = this._events[type]; - length = list.length; - position = -1; - - if (list === listener || - (isFunction(list.listener) && list.listener === listener)) { - delete this._events[type]; - if (this._events.removeListener) - this.emit('removeListener', type, listener); - - } else if (isObject(list)) { - for (i = length; i-- > 0;) { - if (list[i] === listener || - (list[i].listener && list[i].listener === listener)) { - position = i; - break; - } - } - - if (position < 0) - return this; - - if (list.length === 1) { - list.length = 0; - delete this._events[type]; - } else { - list.splice(position, 1); - } - - if (this._events.removeListener) - this.emit('removeListener', type, listener); - } - - return this; -}; - -EventEmitter.prototype.removeAllListeners = function(type) { - var key, listeners; - - if (!this._events) - return this; - - // not listening for removeListener, no need to emit - if (!this._events.removeListener) { - if (arguments.length === 0) - this._events = {}; - else if (this._events[type]) - delete this._events[type]; - return this; - } - - // emit removeListener for all listeners on all events - if (arguments.length === 0) { - for (key in this._events) { - if (key === 'removeListener') continue; - this.removeAllListeners(key); - } - this.removeAllListeners('removeListener'); - this._events = {}; - return this; - } - - listeners = this._events[type]; - - if (isFunction(listeners)) { - this.removeListener(type, listeners); - } else if (listeners) { - // LIFO order - while (listeners.length) - this.removeListener(type, listeners[listeners.length - 1]); - } - delete this._events[type]; - - return this; -}; - -EventEmitter.prototype.listeners = function(type) { - var ret; - if (!this._events || !this._events[type]) - ret = []; - else if (isFunction(this._events[type])) - ret = [this._events[type]]; - else - ret = this._events[type].slice(); - return ret; -}; - -EventEmitter.prototype.listenerCount = function(type) { - if (this._events) { - var evlistener = this._events[type]; - - if (isFunction(evlistener)) - return 1; - else if (evlistener) - return evlistener.length; - } - return 0; -}; - -EventEmitter.listenerCount = function(emitter, type) { - return emitter.listenerCount(type); -}; - -function isFunction(arg) { - return typeof arg === 'function'; -} - -function isNumber(arg) { - return typeof arg === 'number'; -} - -function isObject(arg) { - return typeof arg === 'object' && arg !== null; -} - -function isUndefined(arg) { - return arg === void 0; -} - -},{}],3:[function(require,module,exports){ -(function (global){ -/** - * lodash (Custom Build) - * Build: `lodash modularize exports="npm" -o ./` - * Copyright jQuery Foundation and other contributors - * Released under MIT license - * Based on Underscore.js 1.8.3 - * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - */ - -/** Used as the `TypeError` message for "Functions" methods. */ -var FUNC_ERROR_TEXT = 'Expected a function'; - -/** Used as references for various `Number` constants. */ -var NAN = 0 / 0; - -/** `Object#toString` result references. */ -var symbolTag = '[object Symbol]'; - -/** Used to match leading and trailing whitespace. */ -var reTrim = /^\s+|\s+$/g; - -/** Used to detect bad signed hexadecimal string values. */ -var reIsBadHex = /^[-+]0x[0-9a-f]+$/i; - -/** Used to detect binary string values. */ -var reIsBinary = /^0b[01]+$/i; - -/** Used to detect octal string values. */ -var reIsOctal = /^0o[0-7]+$/i; - -/** Built-in method references without a dependency on `root`. */ -var freeParseInt = parseInt; - -/** Detect free variable `global` from Node.js. */ -var freeGlobal = typeof global == 'object' && global && global.Object === Object && global; - -/** Detect free variable `self`. */ -var freeSelf = typeof self == 'object' && self && self.Object === Object && self; - -/** Used as a reference to the global object. */ -var root = freeGlobal || freeSelf || Function('return this')(); - -/** Used for built-in method references. */ -var objectProto = Object.prototype; - -/** - * Used to resolve the - * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) - * of values. - */ -var objectToString = objectProto.toString; - -/* Built-in method references for those with the same name as other `lodash` methods. */ -var nativeMax = Math.max, - nativeMin = Math.min; - -/** - * Gets the timestamp of the number of milliseconds that have elapsed since - * the Unix epoch (1 January 1970 00:00:00 UTC). - * - * @static - * @memberOf _ - * @since 2.4.0 - * @category Date - * @returns {number} Returns the timestamp. - * @example - * - * _.defer(function(stamp) { - * console.log(_.now() - stamp); - * }, _.now()); - * // => Logs the number of milliseconds it took for the deferred invocation. - */ -var now = function() { - return root.Date.now(); -}; - -/** - * Creates a debounced function that delays invoking `func` until after `wait` - * milliseconds have elapsed since the last time the debounced function was - * invoked. The debounced function comes with a `cancel` method to cancel - * delayed `func` invocations and a `flush` method to immediately invoke them. - * Provide `options` to indicate whether `func` should be invoked on the - * leading and/or trailing edge of the `wait` timeout. The `func` is invoked - * with the last arguments provided to the debounced function. Subsequent - * calls to the debounced function return the result of the last `func` - * invocation. - * - * **Note:** If `leading` and `trailing` options are `true`, `func` is - * invoked on the trailing edge of the timeout only if the debounced function - * is invoked more than once during the `wait` timeout. - * - * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred - * until to the next tick, similar to `setTimeout` with a timeout of `0`. - * - * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/) - * for details over the differences between `_.debounce` and `_.throttle`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Function - * @param {Function} func The function to debounce. - * @param {number} [wait=0] The number of milliseconds to delay. - * @param {Object} [options={}] The options object. - * @param {boolean} [options.leading=false] - * Specify invoking on the leading edge of the timeout. - * @param {number} [options.maxWait] - * The maximum time `func` is allowed to be delayed before it's invoked. - * @param {boolean} [options.trailing=true] - * Specify invoking on the trailing edge of the timeout. - * @returns {Function} Returns the new debounced function. - * @example - * - * // Avoid costly calculations while the window size is in flux. - * jQuery(window).on('resize', _.debounce(calculateLayout, 150)); - * - * // Invoke `sendMail` when clicked, debouncing subsequent calls. - * jQuery(element).on('click', _.debounce(sendMail, 300, { - * 'leading': true, - * 'trailing': false - * })); - * - * // Ensure `batchLog` is invoked once after 1 second of debounced calls. - * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 }); - * var source = new EventSource('/stream'); - * jQuery(source).on('message', debounced); - * - * // Cancel the trailing debounced invocation. - * jQuery(window).on('popstate', debounced.cancel); - */ -function debounce(func, wait, options) { - var lastArgs, - lastThis, - maxWait, - result, - timerId, - lastCallTime, - lastInvokeTime = 0, - leading = false, - maxing = false, - trailing = true; - - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - wait = toNumber(wait) || 0; - if (isObject(options)) { - leading = !!options.leading; - maxing = 'maxWait' in options; - maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait; - trailing = 'trailing' in options ? !!options.trailing : trailing; - } - - function invokeFunc(time) { - var args = lastArgs, - thisArg = lastThis; - - lastArgs = lastThis = undefined; - lastInvokeTime = time; - result = func.apply(thisArg, args); - return result; - } - - function leadingEdge(time) { - // Reset any `maxWait` timer. - lastInvokeTime = time; - // Start the timer for the trailing edge. - timerId = setTimeout(timerExpired, wait); - // Invoke the leading edge. - return leading ? invokeFunc(time) : result; - } - - function remainingWait(time) { - var timeSinceLastCall = time - lastCallTime, - timeSinceLastInvoke = time - lastInvokeTime, - result = wait - timeSinceLastCall; - - return maxing ? nativeMin(result, maxWait - timeSinceLastInvoke) : result; - } - - function shouldInvoke(time) { - var timeSinceLastCall = time - lastCallTime, - timeSinceLastInvoke = time - lastInvokeTime; - - // Either this is the first call, activity has stopped and we're at the - // trailing edge, the system time has gone backwards and we're treating - // it as the trailing edge, or we've hit the `maxWait` limit. - return (lastCallTime === undefined || (timeSinceLastCall >= wait) || - (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait)); - } - - function timerExpired() { - var time = now(); - if (shouldInvoke(time)) { - return trailingEdge(time); - } - // Restart the timer. - timerId = setTimeout(timerExpired, remainingWait(time)); - } - - function trailingEdge(time) { - timerId = undefined; - - // Only invoke if we have `lastArgs` which means `func` has been - // debounced at least once. - if (trailing && lastArgs) { - return invokeFunc(time); - } - lastArgs = lastThis = undefined; - return result; - } - - function cancel() { - if (timerId !== undefined) { - clearTimeout(timerId); - } - lastInvokeTime = 0; - lastArgs = lastCallTime = lastThis = timerId = undefined; - } - - function flush() { - return timerId === undefined ? result : trailingEdge(now()); - } - - function debounced() { - var time = now(), - isInvoking = shouldInvoke(time); - - lastArgs = arguments; - lastThis = this; - lastCallTime = time; - - if (isInvoking) { - if (timerId === undefined) { - return leadingEdge(lastCallTime); - } - if (maxing) { - // Handle invocations in a tight loop. - timerId = setTimeout(timerExpired, wait); - return invokeFunc(lastCallTime); - } - } - if (timerId === undefined) { - timerId = setTimeout(timerExpired, wait); - } - return result; - } - debounced.cancel = cancel; - debounced.flush = flush; - return debounced; -} - -/** - * Checks if `value` is the - * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types) - * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an object, else `false`. - * @example - * - * _.isObject({}); - * // => true - * - * _.isObject([1, 2, 3]); - * // => true - * - * _.isObject(_.noop); - * // => true - * - * _.isObject(null); - * // => false - */ -function isObject(value) { - var type = typeof value; - return !!value && (type == 'object' || type == 'function'); -} - -/** - * Checks if `value` is object-like. A value is object-like if it's not `null` - * and has a `typeof` result of "object". - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is object-like, else `false`. - * @example - * - * _.isObjectLike({}); - * // => true - * - * _.isObjectLike([1, 2, 3]); - * // => true - * - * _.isObjectLike(_.noop); - * // => false - * - * _.isObjectLike(null); - * // => false - */ -function isObjectLike(value) { - return !!value && typeof value == 'object'; -} - -/** - * Checks if `value` is classified as a `Symbol` primitive or object. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a symbol, else `false`. - * @example - * - * _.isSymbol(Symbol.iterator); - * // => true - * - * _.isSymbol('abc'); - * // => false - */ -function isSymbol(value) { - return typeof value == 'symbol' || - (isObjectLike(value) && objectToString.call(value) == symbolTag); -} - -/** - * Converts `value` to a number. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to process. - * @returns {number} Returns the number. - * @example - * - * _.toNumber(3.2); - * // => 3.2 - * - * _.toNumber(Number.MIN_VALUE); - * // => 5e-324 - * - * _.toNumber(Infinity); - * // => Infinity - * - * _.toNumber('3.2'); - * // => 3.2 - */ -function toNumber(value) { - if (typeof value == 'number') { - return value; - } - if (isSymbol(value)) { - return NAN; - } - if (isObject(value)) { - var other = typeof value.valueOf == 'function' ? value.valueOf() : value; - value = isObject(other) ? (other + '') : other; - } - if (typeof value != 'string') { - return value === 0 ? value : +value; - } - value = value.replace(reTrim, ''); - var isBinary = reIsBinary.test(value); - return (isBinary || reIsOctal.test(value)) - ? freeParseInt(value.slice(2), isBinary ? 2 : 8) - : (reIsBadHex.test(value) ? NAN : +value); -} - -module.exports = debounce; - -}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{}],4:[function(require,module,exports){ -(function (global){ -/** - * lodash (Custom Build) - * Build: `lodash modularize exports="npm" -o ./` - * Copyright jQuery Foundation and other contributors - * Released under MIT license - * Based on Underscore.js 1.8.3 - * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - */ - -/** Used as the size to enable large array optimizations. */ -var LARGE_ARRAY_SIZE = 200; - -/** Used to stand-in for `undefined` hash values. */ -var HASH_UNDEFINED = '__lodash_hash_undefined__'; - -/** Used to compose bitmasks for comparison styles. */ -var UNORDERED_COMPARE_FLAG = 1, - PARTIAL_COMPARE_FLAG = 2; - -/** Used as references for various `Number` constants. */ -var MAX_SAFE_INTEGER = 9007199254740991; - -/** `Object#toString` result references. */ -var argsTag = '[object Arguments]', - arrayTag = '[object Array]', - boolTag = '[object Boolean]', - dateTag = '[object Date]', - errorTag = '[object Error]', - funcTag = '[object Function]', - genTag = '[object GeneratorFunction]', - mapTag = '[object Map]', - numberTag = '[object Number]', - objectTag = '[object Object]', - promiseTag = '[object Promise]', - regexpTag = '[object RegExp]', - setTag = '[object Set]', - stringTag = '[object String]', - symbolTag = '[object Symbol]', - weakMapTag = '[object WeakMap]'; - -var arrayBufferTag = '[object ArrayBuffer]', - dataViewTag = '[object DataView]', - float32Tag = '[object Float32Array]', - float64Tag = '[object Float64Array]', - int8Tag = '[object Int8Array]', - int16Tag = '[object Int16Array]', - int32Tag = '[object Int32Array]', - uint8Tag = '[object Uint8Array]', - uint8ClampedTag = '[object Uint8ClampedArray]', - uint16Tag = '[object Uint16Array]', - uint32Tag = '[object Uint32Array]'; - -/** - * Used to match `RegExp` - * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns). - */ -var reRegExpChar = /[\\^$.*+?()[\]{}|]/g; - -/** Used to detect host constructors (Safari). */ -var reIsHostCtor = /^\[object .+?Constructor\]$/; - -/** Used to detect unsigned integer values. */ -var reIsUint = /^(?:0|[1-9]\d*)$/; - -/** Used to identify `toStringTag` values of typed arrays. */ -var typedArrayTags = {}; -typedArrayTags[float32Tag] = typedArrayTags[float64Tag] = -typedArrayTags[int8Tag] = typedArrayTags[int16Tag] = -typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] = -typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] = -typedArrayTags[uint32Tag] = true; -typedArrayTags[argsTag] = typedArrayTags[arrayTag] = -typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] = -typedArrayTags[dataViewTag] = typedArrayTags[dateTag] = -typedArrayTags[errorTag] = typedArrayTags[funcTag] = -typedArrayTags[mapTag] = typedArrayTags[numberTag] = -typedArrayTags[objectTag] = typedArrayTags[regexpTag] = -typedArrayTags[setTag] = typedArrayTags[stringTag] = -typedArrayTags[weakMapTag] = false; - -/** Detect free variable `global` from Node.js. */ -var freeGlobal = typeof global == 'object' && global && global.Object === Object && global; - -/** Detect free variable `self`. */ -var freeSelf = typeof self == 'object' && self && self.Object === Object && self; - -/** Used as a reference to the global object. */ -var root = freeGlobal || freeSelf || Function('return this')(); - -/** Detect free variable `exports`. */ -var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports; - -/** Detect free variable `module`. */ -var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module; - -/** Detect the popular CommonJS extension `module.exports`. */ -var moduleExports = freeModule && freeModule.exports === freeExports; - -/** Detect free variable `process` from Node.js. */ -var freeProcess = moduleExports && freeGlobal.process; - -/** Used to access faster Node.js helpers. */ -var nodeUtil = (function() { - try { - return freeProcess && freeProcess.binding('util'); - } catch (e) {} -}()); - -/* Node.js helper references. */ -var nodeIsTypedArray = nodeUtil && nodeUtil.isTypedArray; - -/** - * A specialized version of `_.some` for arrays without support for iteratee - * shorthands. - * - * @private - * @param {Array} [array] The array to iterate over. - * @param {Function} predicate The function invoked per iteration. - * @returns {boolean} Returns `true` if any element passes the predicate check, - * else `false`. - */ -function arraySome(array, predicate) { - var index = -1, - length = array ? array.length : 0; - - while (++index < length) { - if (predicate(array[index], index, array)) { - return true; - } - } - return false; -} - -/** - * The base implementation of `_.times` without support for iteratee shorthands - * or max array length checks. - * - * @private - * @param {number} n The number of times to invoke `iteratee`. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array} Returns the array of results. - */ -function baseTimes(n, iteratee) { - var index = -1, - result = Array(n); - - while (++index < n) { - result[index] = iteratee(index); - } - return result; -} - -/** - * The base implementation of `_.unary` without support for storing metadata. - * - * @private - * @param {Function} func The function to cap arguments for. - * @returns {Function} Returns the new capped function. - */ -function baseUnary(func) { - return function(value) { - return func(value); - }; -} - -/** - * Gets the value at `key` of `object`. - * - * @private - * @param {Object} [object] The object to query. - * @param {string} key The key of the property to get. - * @returns {*} Returns the property value. - */ -function getValue(object, key) { - return object == null ? undefined : object[key]; -} - -/** - * Checks if `value` is a host object in IE < 9. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a host object, else `false`. - */ -function isHostObject(value) { - // Many host objects are `Object` objects that can coerce to strings - // despite having improperly defined `toString` methods. - var result = false; - if (value != null && typeof value.toString != 'function') { - try { - result = !!(value + ''); - } catch (e) {} - } - return result; -} - -/** - * Converts `map` to its key-value pairs. - * - * @private - * @param {Object} map The map to convert. - * @returns {Array} Returns the key-value pairs. - */ -function mapToArray(map) { - var index = -1, - result = Array(map.size); - - map.forEach(function(value, key) { - result[++index] = [key, value]; - }); - return result; -} - -/** - * Creates a unary function that invokes `func` with its argument transformed. - * - * @private - * @param {Function} func The function to wrap. - * @param {Function} transform The argument transform. - * @returns {Function} Returns the new function. - */ -function overArg(func, transform) { - return function(arg) { - return func(transform(arg)); - }; -} - -/** - * Converts `set` to an array of its values. - * - * @private - * @param {Object} set The set to convert. - * @returns {Array} Returns the values. - */ -function setToArray(set) { - var index = -1, - result = Array(set.size); - - set.forEach(function(value) { - result[++index] = value; - }); - return result; -} - -/** Used for built-in method references. */ -var arrayProto = Array.prototype, - funcProto = Function.prototype, - objectProto = Object.prototype; - -/** Used to detect overreaching core-js shims. */ -var coreJsData = root['__core-js_shared__']; - -/** Used to detect methods masquerading as native. */ -var maskSrcKey = (function() { - var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || ''); - return uid ? ('Symbol(src)_1.' + uid) : ''; -}()); - -/** Used to resolve the decompiled source of functions. */ -var funcToString = funcProto.toString; - -/** Used to check objects for own properties. */ -var hasOwnProperty = objectProto.hasOwnProperty; - -/** - * Used to resolve the - * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) - * of values. - */ -var objectToString = objectProto.toString; - -/** Used to detect if a method is native. */ -var reIsNative = RegExp('^' + - funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\$&') - .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' -); - -/** Built-in value references. */ -var Symbol = root.Symbol, - Uint8Array = root.Uint8Array, - propertyIsEnumerable = objectProto.propertyIsEnumerable, - splice = arrayProto.splice; - -/* Built-in method references for those with the same name as other `lodash` methods. */ -var nativeKeys = overArg(Object.keys, Object); - -/* Built-in method references that are verified to be native. */ -var DataView = getNative(root, 'DataView'), - Map = getNative(root, 'Map'), - Promise = getNative(root, 'Promise'), - Set = getNative(root, 'Set'), - WeakMap = getNative(root, 'WeakMap'), - nativeCreate = getNative(Object, 'create'); - -/** Used to detect maps, sets, and weakmaps. */ -var dataViewCtorString = toSource(DataView), - mapCtorString = toSource(Map), - promiseCtorString = toSource(Promise), - setCtorString = toSource(Set), - weakMapCtorString = toSource(WeakMap); - -/** Used to convert symbols to primitives and strings. */ -var symbolProto = Symbol ? Symbol.prototype : undefined, - symbolValueOf = symbolProto ? symbolProto.valueOf : undefined; - -/** - * Creates a hash object. - * - * @private - * @constructor - * @param {Array} [entries] The key-value pairs to cache. - */ -function Hash(entries) { - var index = -1, - length = entries ? entries.length : 0; - - this.clear(); - while (++index < length) { - var entry = entries[index]; - this.set(entry[0], entry[1]); - } -} - -/** - * Removes all key-value entries from the hash. - * - * @private - * @name clear - * @memberOf Hash - */ -function hashClear() { - this.__data__ = nativeCreate ? nativeCreate(null) : {}; -} - -/** - * Removes `key` and its value from the hash. - * - * @private - * @name delete - * @memberOf Hash - * @param {Object} hash The hash to modify. - * @param {string} key The key of the value to remove. - * @returns {boolean} Returns `true` if the entry was removed, else `false`. - */ -function hashDelete(key) { - return this.has(key) && delete this.__data__[key]; -} - -/** - * Gets the hash value for `key`. - * - * @private - * @name get - * @memberOf Hash - * @param {string} key The key of the value to get. - * @returns {*} Returns the entry value. - */ -function hashGet(key) { - var data = this.__data__; - if (nativeCreate) { - var result = data[key]; - return result === HASH_UNDEFINED ? undefined : result; - } - return hasOwnProperty.call(data, key) ? data[key] : undefined; -} - -/** - * Checks if a hash value for `key` exists. - * - * @private - * @name has - * @memberOf Hash - * @param {string} key The key of the entry to check. - * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. - */ -function hashHas(key) { - var data = this.__data__; - return nativeCreate ? data[key] !== undefined : hasOwnProperty.call(data, key); -} - -/** - * Sets the hash `key` to `value`. - * - * @private - * @name set - * @memberOf Hash - * @param {string} key The key of the value to set. - * @param {*} value The value to set. - * @returns {Object} Returns the hash instance. - */ -function hashSet(key, value) { - var data = this.__data__; - data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value; - return this; -} - -// Add methods to `Hash`. -Hash.prototype.clear = hashClear; -Hash.prototype['delete'] = hashDelete; -Hash.prototype.get = hashGet; -Hash.prototype.has = hashHas; -Hash.prototype.set = hashSet; - -/** - * Creates an list cache object. - * - * @private - * @constructor - * @param {Array} [entries] The key-value pairs to cache. - */ -function ListCache(entries) { - var index = -1, - length = entries ? entries.length : 0; - - this.clear(); - while (++index < length) { - var entry = entries[index]; - this.set(entry[0], entry[1]); - } -} - -/** - * Removes all key-value entries from the list cache. - * - * @private - * @name clear - * @memberOf ListCache - */ -function listCacheClear() { - this.__data__ = []; -} - -/** - * Removes `key` and its value from the list cache. - * - * @private - * @name delete - * @memberOf ListCache - * @param {string} key The key of the value to remove. - * @returns {boolean} Returns `true` if the entry was removed, else `false`. - */ -function listCacheDelete(key) { - var data = this.__data__, - index = assocIndexOf(data, key); - - if (index < 0) { - return false; - } - var lastIndex = data.length - 1; - if (index == lastIndex) { - data.pop(); - } else { - splice.call(data, index, 1); - } - return true; -} - -/** - * Gets the list cache value for `key`. - * - * @private - * @name get - * @memberOf ListCache - * @param {string} key The key of the value to get. - * @returns {*} Returns the entry value. - */ -function listCacheGet(key) { - var data = this.__data__, - index = assocIndexOf(data, key); - - return index < 0 ? undefined : data[index][1]; -} - -/** - * Checks if a list cache value for `key` exists. - * - * @private - * @name has - * @memberOf ListCache - * @param {string} key The key of the entry to check. - * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. - */ -function listCacheHas(key) { - return assocIndexOf(this.__data__, key) > -1; -} - -/** - * Sets the list cache `key` to `value`. - * - * @private - * @name set - * @memberOf ListCache - * @param {string} key The key of the value to set. - * @param {*} value The value to set. - * @returns {Object} Returns the list cache instance. - */ -function listCacheSet(key, value) { - var data = this.__data__, - index = assocIndexOf(data, key); - - if (index < 0) { - data.push([key, value]); - } else { - data[index][1] = value; - } - return this; -} - -// Add methods to `ListCache`. -ListCache.prototype.clear = listCacheClear; -ListCache.prototype['delete'] = listCacheDelete; -ListCache.prototype.get = listCacheGet; -ListCache.prototype.has = listCacheHas; -ListCache.prototype.set = listCacheSet; - -/** - * Creates a map cache object to store key-value pairs. - * - * @private - * @constructor - * @param {Array} [entries] The key-value pairs to cache. - */ -function MapCache(entries) { - var index = -1, - length = entries ? entries.length : 0; - - this.clear(); - while (++index < length) { - var entry = entries[index]; - this.set(entry[0], entry[1]); - } -} - -/** - * Removes all key-value entries from the map. - * - * @private - * @name clear - * @memberOf MapCache - */ -function mapCacheClear() { - this.__data__ = { - 'hash': new Hash, - 'map': new (Map || ListCache), - 'string': new Hash - }; -} - -/** - * Removes `key` and its value from the map. - * - * @private - * @name delete - * @memberOf MapCache - * @param {string} key The key of the value to remove. - * @returns {boolean} Returns `true` if the entry was removed, else `false`. - */ -function mapCacheDelete(key) { - return getMapData(this, key)['delete'](key); -} - -/** - * Gets the map value for `key`. - * - * @private - * @name get - * @memberOf MapCache - * @param {string} key The key of the value to get. - * @returns {*} Returns the entry value. - */ -function mapCacheGet(key) { - return getMapData(this, key).get(key); -} - -/** - * Checks if a map value for `key` exists. - * - * @private - * @name has - * @memberOf MapCache - * @param {string} key The key of the entry to check. - * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. - */ -function mapCacheHas(key) { - return getMapData(this, key).has(key); -} - -/** - * Sets the map `key` to `value`. - * - * @private - * @name set - * @memberOf MapCache - * @param {string} key The key of the value to set. - * @param {*} value The value to set. - * @returns {Object} Returns the map cache instance. - */ -function mapCacheSet(key, value) { - getMapData(this, key).set(key, value); - return this; -} - -// Add methods to `MapCache`. -MapCache.prototype.clear = mapCacheClear; -MapCache.prototype['delete'] = mapCacheDelete; -MapCache.prototype.get = mapCacheGet; -MapCache.prototype.has = mapCacheHas; -MapCache.prototype.set = mapCacheSet; - -/** - * - * Creates an array cache object to store unique values. - * - * @private - * @constructor - * @param {Array} [values] The values to cache. - */ -function SetCache(values) { - var index = -1, - length = values ? values.length : 0; - - this.__data__ = new MapCache; - while (++index < length) { - this.add(values[index]); - } -} - -/** - * Adds `value` to the array cache. - * - * @private - * @name add - * @memberOf SetCache - * @alias push - * @param {*} value The value to cache. - * @returns {Object} Returns the cache instance. - */ -function setCacheAdd(value) { - this.__data__.set(value, HASH_UNDEFINED); - return this; -} - -/** - * Checks if `value` is in the array cache. - * - * @private - * @name has - * @memberOf SetCache - * @param {*} value The value to search for. - * @returns {number} Returns `true` if `value` is found, else `false`. - */ -function setCacheHas(value) { - return this.__data__.has(value); -} - -// Add methods to `SetCache`. -SetCache.prototype.add = SetCache.prototype.push = setCacheAdd; -SetCache.prototype.has = setCacheHas; - -/** - * Creates a stack cache object to store key-value pairs. - * - * @private - * @constructor - * @param {Array} [entries] The key-value pairs to cache. - */ -function Stack(entries) { - this.__data__ = new ListCache(entries); -} - -/** - * Removes all key-value entries from the stack. - * - * @private - * @name clear - * @memberOf Stack - */ -function stackClear() { - this.__data__ = new ListCache; -} - -/** - * Removes `key` and its value from the stack. - * - * @private - * @name delete - * @memberOf Stack - * @param {string} key The key of the value to remove. - * @returns {boolean} Returns `true` if the entry was removed, else `false`. - */ -function stackDelete(key) { - return this.__data__['delete'](key); -} - -/** - * Gets the stack value for `key`. - * - * @private - * @name get - * @memberOf Stack - * @param {string} key The key of the value to get. - * @returns {*} Returns the entry value. - */ -function stackGet(key) { - return this.__data__.get(key); -} - -/** - * Checks if a stack value for `key` exists. - * - * @private - * @name has - * @memberOf Stack - * @param {string} key The key of the entry to check. - * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. - */ -function stackHas(key) { - return this.__data__.has(key); -} - -/** - * Sets the stack `key` to `value`. - * - * @private - * @name set - * @memberOf Stack - * @param {string} key The key of the value to set. - * @param {*} value The value to set. - * @returns {Object} Returns the stack cache instance. - */ -function stackSet(key, value) { - var cache = this.__data__; - if (cache instanceof ListCache) { - var pairs = cache.__data__; - if (!Map || (pairs.length < LARGE_ARRAY_SIZE - 1)) { - pairs.push([key, value]); - return this; - } - cache = this.__data__ = new MapCache(pairs); - } - cache.set(key, value); - return this; -} - -// Add methods to `Stack`. -Stack.prototype.clear = stackClear; -Stack.prototype['delete'] = stackDelete; -Stack.prototype.get = stackGet; -Stack.prototype.has = stackHas; -Stack.prototype.set = stackSet; - -/** - * Creates an array of the enumerable property names of the array-like `value`. - * - * @private - * @param {*} value The value to query. - * @param {boolean} inherited Specify returning inherited property names. - * @returns {Array} Returns the array of property names. - */ -function arrayLikeKeys(value, inherited) { - // Safari 8.1 makes `arguments.callee` enumerable in strict mode. - // Safari 9 makes `arguments.length` enumerable in strict mode. - var result = (isArray(value) || isArguments(value)) - ? baseTimes(value.length, String) - : []; - - var length = result.length, - skipIndexes = !!length; - - for (var key in value) { - if ((inherited || hasOwnProperty.call(value, key)) && - !(skipIndexes && (key == 'length' || isIndex(key, length)))) { - result.push(key); - } - } - return result; -} - -/** - * Gets the index at which the `key` is found in `array` of key-value pairs. - * - * @private - * @param {Array} array The array to inspect. - * @param {*} key The key to search for. - * @returns {number} Returns the index of the matched value, else `-1`. - */ -function assocIndexOf(array, key) { - var length = array.length; - while (length--) { - if (eq(array[length][0], key)) { - return length; - } - } - return -1; -} - -/** - * The base implementation of `getTag`. - * - * @private - * @param {*} value The value to query. - * @returns {string} Returns the `toStringTag`. - */ -function baseGetTag(value) { - return objectToString.call(value); -} - -/** - * The base implementation of `_.isEqual` which supports partial comparisons - * and tracks traversed objects. - * - * @private - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @param {Function} [customizer] The function to customize comparisons. - * @param {boolean} [bitmask] The bitmask of comparison flags. - * The bitmask may be composed of the following flags: - * 1 - Unordered comparison - * 2 - Partial comparison - * @param {Object} [stack] Tracks traversed `value` and `other` objects. - * @returns {boolean} Returns `true` if the values are equivalent, else `false`. - */ -function baseIsEqual(value, other, customizer, bitmask, stack) { - if (value === other) { - return true; - } - if (value == null || other == null || (!isObject(value) && !isObjectLike(other))) { - return value !== value && other !== other; - } - return baseIsEqualDeep(value, other, baseIsEqual, customizer, bitmask, stack); -} - -/** - * A specialized version of `baseIsEqual` for arrays and objects which performs - * deep comparisons and tracks traversed objects enabling objects with circular - * references to be compared. - * - * @private - * @param {Object} object The object to compare. - * @param {Object} other The other object to compare. - * @param {Function} equalFunc The function to determine equivalents of values. - * @param {Function} [customizer] The function to customize comparisons. - * @param {number} [bitmask] The bitmask of comparison flags. See `baseIsEqual` - * for more details. - * @param {Object} [stack] Tracks traversed `object` and `other` objects. - * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. - */ -function baseIsEqualDeep(object, other, equalFunc, customizer, bitmask, stack) { - var objIsArr = isArray(object), - othIsArr = isArray(other), - objTag = arrayTag, - othTag = arrayTag; - - if (!objIsArr) { - objTag = getTag(object); - objTag = objTag == argsTag ? objectTag : objTag; - } - if (!othIsArr) { - othTag = getTag(other); - othTag = othTag == argsTag ? objectTag : othTag; - } - var objIsObj = objTag == objectTag && !isHostObject(object), - othIsObj = othTag == objectTag && !isHostObject(other), - isSameTag = objTag == othTag; - - if (isSameTag && !objIsObj) { - stack || (stack = new Stack); - return (objIsArr || isTypedArray(object)) - ? equalArrays(object, other, equalFunc, customizer, bitmask, stack) - : equalByTag(object, other, objTag, equalFunc, customizer, bitmask, stack); - } - if (!(bitmask & PARTIAL_COMPARE_FLAG)) { - var objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'), - othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__'); - - if (objIsWrapped || othIsWrapped) { - var objUnwrapped = objIsWrapped ? object.value() : object, - othUnwrapped = othIsWrapped ? other.value() : other; - - stack || (stack = new Stack); - return equalFunc(objUnwrapped, othUnwrapped, customizer, bitmask, stack); - } - } - if (!isSameTag) { - return false; - } - stack || (stack = new Stack); - return equalObjects(object, other, equalFunc, customizer, bitmask, stack); -} - -/** - * The base implementation of `_.isNative` without bad shim checks. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a native function, - * else `false`. - */ -function baseIsNative(value) { - if (!isObject(value) || isMasked(value)) { - return false; - } - var pattern = (isFunction(value) || isHostObject(value)) ? reIsNative : reIsHostCtor; - return pattern.test(toSource(value)); -} - -/** - * The base implementation of `_.isTypedArray` without Node.js optimizations. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a typed array, else `false`. - */ -function baseIsTypedArray(value) { - return isObjectLike(value) && - isLength(value.length) && !!typedArrayTags[objectToString.call(value)]; -} - -/** - * The base implementation of `_.keys` which doesn't treat sparse arrays as dense. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names. - */ -function baseKeys(object) { - if (!isPrototype(object)) { - return nativeKeys(object); - } - var result = []; - for (var key in Object(object)) { - if (hasOwnProperty.call(object, key) && key != 'constructor') { - result.push(key); - } - } - return result; -} - -/** - * A specialized version of `baseIsEqualDeep` for arrays with support for - * partial deep comparisons. - * - * @private - * @param {Array} array The array to compare. - * @param {Array} other The other array to compare. - * @param {Function} equalFunc The function to determine equivalents of values. - * @param {Function} customizer The function to customize comparisons. - * @param {number} bitmask The bitmask of comparison flags. See `baseIsEqual` - * for more details. - * @param {Object} stack Tracks traversed `array` and `other` objects. - * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`. - */ -function equalArrays(array, other, equalFunc, customizer, bitmask, stack) { - var isPartial = bitmask & PARTIAL_COMPARE_FLAG, - arrLength = array.length, - othLength = other.length; - - if (arrLength != othLength && !(isPartial && othLength > arrLength)) { - return false; - } - // Assume cyclic values are equal. - var stacked = stack.get(array); - if (stacked && stack.get(other)) { - return stacked == other; - } - var index = -1, - result = true, - seen = (bitmask & UNORDERED_COMPARE_FLAG) ? new SetCache : undefined; - - stack.set(array, other); - stack.set(other, array); - - // Ignore non-index properties. - while (++index < arrLength) { - var arrValue = array[index], - othValue = other[index]; - - if (customizer) { - var compared = isPartial - ? customizer(othValue, arrValue, index, other, array, stack) - : customizer(arrValue, othValue, index, array, other, stack); - } - if (compared !== undefined) { - if (compared) { - continue; - } - result = false; - break; - } - // Recursively compare arrays (susceptible to call stack limits). - if (seen) { - if (!arraySome(other, function(othValue, othIndex) { - if (!seen.has(othIndex) && - (arrValue === othValue || equalFunc(arrValue, othValue, customizer, bitmask, stack))) { - return seen.add(othIndex); - } - })) { - result = false; - break; - } - } else if (!( - arrValue === othValue || - equalFunc(arrValue, othValue, customizer, bitmask, stack) - )) { - result = false; - break; - } - } - stack['delete'](array); - stack['delete'](other); - return result; -} - -/** - * A specialized version of `baseIsEqualDeep` for comparing objects of - * the same `toStringTag`. - * - * **Note:** This function only supports comparing values with tags of - * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`. - * - * @private - * @param {Object} object The object to compare. - * @param {Object} other The other object to compare. - * @param {string} tag The `toStringTag` of the objects to compare. - * @param {Function} equalFunc The function to determine equivalents of values. - * @param {Function} customizer The function to customize comparisons. - * @param {number} bitmask The bitmask of comparison flags. See `baseIsEqual` - * for more details. - * @param {Object} stack Tracks traversed `object` and `other` objects. - * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. - */ -function equalByTag(object, other, tag, equalFunc, customizer, bitmask, stack) { - switch (tag) { - case dataViewTag: - if ((object.byteLength != other.byteLength) || - (object.byteOffset != other.byteOffset)) { - return false; - } - object = object.buffer; - other = other.buffer; - - case arrayBufferTag: - if ((object.byteLength != other.byteLength) || - !equalFunc(new Uint8Array(object), new Uint8Array(other))) { - return false; - } - return true; - - case boolTag: - case dateTag: - case numberTag: - // Coerce booleans to `1` or `0` and dates to milliseconds. - // Invalid dates are coerced to `NaN`. - return eq(+object, +other); - - case errorTag: - return object.name == other.name && object.message == other.message; - - case regexpTag: - case stringTag: - // Coerce regexes to strings and treat strings, primitives and objects, - // as equal. See http://www.ecma-international.org/ecma-262/7.0/#sec-regexp.prototype.tostring - // for more details. - return object == (other + ''); - - case mapTag: - var convert = mapToArray; - - case setTag: - var isPartial = bitmask & PARTIAL_COMPARE_FLAG; - convert || (convert = setToArray); - - if (object.size != other.size && !isPartial) { - return false; - } - // Assume cyclic values are equal. - var stacked = stack.get(object); - if (stacked) { - return stacked == other; - } - bitmask |= UNORDERED_COMPARE_FLAG; - - // Recursively compare objects (susceptible to call stack limits). - stack.set(object, other); - var result = equalArrays(convert(object), convert(other), equalFunc, customizer, bitmask, stack); - stack['delete'](object); - return result; - - case symbolTag: - if (symbolValueOf) { - return symbolValueOf.call(object) == symbolValueOf.call(other); - } - } - return false; -} - -/** - * A specialized version of `baseIsEqualDeep` for objects with support for - * partial deep comparisons. - * - * @private - * @param {Object} object The object to compare. - * @param {Object} other The other object to compare. - * @param {Function} equalFunc The function to determine equivalents of values. - * @param {Function} customizer The function to customize comparisons. - * @param {number} bitmask The bitmask of comparison flags. See `baseIsEqual` - * for more details. - * @param {Object} stack Tracks traversed `object` and `other` objects. - * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. - */ -function equalObjects(object, other, equalFunc, customizer, bitmask, stack) { - var isPartial = bitmask & PARTIAL_COMPARE_FLAG, - objProps = keys(object), - objLength = objProps.length, - othProps = keys(other), - othLength = othProps.length; - - if (objLength != othLength && !isPartial) { - return false; - } - var index = objLength; - while (index--) { - var key = objProps[index]; - if (!(isPartial ? key in other : hasOwnProperty.call(other, key))) { - return false; - } - } - // Assume cyclic values are equal. - var stacked = stack.get(object); - if (stacked && stack.get(other)) { - return stacked == other; - } - var result = true; - stack.set(object, other); - stack.set(other, object); - - var skipCtor = isPartial; - while (++index < objLength) { - key = objProps[index]; - var objValue = object[key], - othValue = other[key]; - - if (customizer) { - var compared = isPartial - ? customizer(othValue, objValue, key, other, object, stack) - : customizer(objValue, othValue, key, object, other, stack); - } - // Recursively compare objects (susceptible to call stack limits). - if (!(compared === undefined - ? (objValue === othValue || equalFunc(objValue, othValue, customizer, bitmask, stack)) - : compared - )) { - result = false; - break; - } - skipCtor || (skipCtor = key == 'constructor'); - } - if (result && !skipCtor) { - var objCtor = object.constructor, - othCtor = other.constructor; - - // Non `Object` object instances with different constructors are not equal. - if (objCtor != othCtor && - ('constructor' in object && 'constructor' in other) && - !(typeof objCtor == 'function' && objCtor instanceof objCtor && - typeof othCtor == 'function' && othCtor instanceof othCtor)) { - result = false; - } - } - stack['delete'](object); - stack['delete'](other); - return result; -} - -/** - * Gets the data for `map`. - * - * @private - * @param {Object} map The map to query. - * @param {string} key The reference key. - * @returns {*} Returns the map data. - */ -function getMapData(map, key) { - var data = map.__data__; - return isKeyable(key) - ? data[typeof key == 'string' ? 'string' : 'hash'] - : data.map; -} - -/** - * Gets the native function at `key` of `object`. - * - * @private - * @param {Object} object The object to query. - * @param {string} key The key of the method to get. - * @returns {*} Returns the function if it's native, else `undefined`. - */ -function getNative(object, key) { - var value = getValue(object, key); - return baseIsNative(value) ? value : undefined; -} - -/** - * Gets the `toStringTag` of `value`. - * - * @private - * @param {*} value The value to query. - * @returns {string} Returns the `toStringTag`. - */ -var getTag = baseGetTag; - -// Fallback for data views, maps, sets, and weak maps in IE 11, -// for data views in Edge < 14, and promises in Node.js. -if ((DataView && getTag(new DataView(new ArrayBuffer(1))) != dataViewTag) || - (Map && getTag(new Map) != mapTag) || - (Promise && getTag(Promise.resolve()) != promiseTag) || - (Set && getTag(new Set) != setTag) || - (WeakMap && getTag(new WeakMap) != weakMapTag)) { - getTag = function(value) { - var result = objectToString.call(value), - Ctor = result == objectTag ? value.constructor : undefined, - ctorString = Ctor ? toSource(Ctor) : undefined; - - if (ctorString) { - switch (ctorString) { - case dataViewCtorString: return dataViewTag; - case mapCtorString: return mapTag; - case promiseCtorString: return promiseTag; - case setCtorString: return setTag; - case weakMapCtorString: return weakMapTag; - } - } - return result; - }; -} - -/** - * Checks if `value` is a valid array-like index. - * - * @private - * @param {*} value The value to check. - * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index. - * @returns {boolean} Returns `true` if `value` is a valid index, else `false`. - */ -function isIndex(value, length) { - length = length == null ? MAX_SAFE_INTEGER : length; - return !!length && - (typeof value == 'number' || reIsUint.test(value)) && - (value > -1 && value % 1 == 0 && value < length); -} - -/** - * Checks if `value` is suitable for use as unique object key. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is suitable, else `false`. - */ -function isKeyable(value) { - var type = typeof value; - return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean') - ? (value !== '__proto__') - : (value === null); -} - -/** - * Checks if `func` has its source masked. - * - * @private - * @param {Function} func The function to check. - * @returns {boolean} Returns `true` if `func` is masked, else `false`. - */ -function isMasked(func) { - return !!maskSrcKey && (maskSrcKey in func); -} - -/** - * Checks if `value` is likely a prototype object. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a prototype, else `false`. - */ -function isPrototype(value) { - var Ctor = value && value.constructor, - proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto; - - return value === proto; -} - -/** - * Converts `func` to its source code. - * - * @private - * @param {Function} func The function to process. - * @returns {string} Returns the source code. - */ -function toSource(func) { - if (func != null) { - try { - return funcToString.call(func); - } catch (e) {} - try { - return (func + ''); - } catch (e) {} - } - return ''; -} - -/** - * Performs a - * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * comparison between two values to determine if they are equivalent. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if the values are equivalent, else `false`. - * @example - * - * var object = { 'a': 1 }; - * var other = { 'a': 1 }; - * - * _.eq(object, object); - * // => true - * - * _.eq(object, other); - * // => false - * - * _.eq('a', 'a'); - * // => true - * - * _.eq('a', Object('a')); - * // => false - * - * _.eq(NaN, NaN); - * // => true - */ -function eq(value, other) { - return value === other || (value !== value && other !== other); -} - -/** - * Checks if `value` is likely an `arguments` object. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an `arguments` object, - * else `false`. - * @example - * - * _.isArguments(function() { return arguments; }()); - * // => true - * - * _.isArguments([1, 2, 3]); - * // => false - */ -function isArguments(value) { - // Safari 8.1 makes `arguments.callee` enumerable in strict mode. - return isArrayLikeObject(value) && hasOwnProperty.call(value, 'callee') && - (!propertyIsEnumerable.call(value, 'callee') || objectToString.call(value) == argsTag); -} - -/** - * Checks if `value` is classified as an `Array` object. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an array, else `false`. - * @example - * - * _.isArray([1, 2, 3]); - * // => true - * - * _.isArray(document.body.children); - * // => false - * - * _.isArray('abc'); - * // => false - * - * _.isArray(_.noop); - * // => false - */ -var isArray = Array.isArray; - -/** - * Checks if `value` is array-like. A value is considered array-like if it's - * not a function and has a `value.length` that's an integer greater than or - * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is array-like, else `false`. - * @example - * - * _.isArrayLike([1, 2, 3]); - * // => true - * - * _.isArrayLike(document.body.children); - * // => true - * - * _.isArrayLike('abc'); - * // => true - * - * _.isArrayLike(_.noop); - * // => false - */ -function isArrayLike(value) { - return value != null && isLength(value.length) && !isFunction(value); -} - -/** - * This method is like `_.isArrayLike` except that it also checks if `value` - * is an object. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an array-like object, - * else `false`. - * @example - * - * _.isArrayLikeObject([1, 2, 3]); - * // => true - * - * _.isArrayLikeObject(document.body.children); - * // => true - * - * _.isArrayLikeObject('abc'); - * // => false - * - * _.isArrayLikeObject(_.noop); - * // => false - */ -function isArrayLikeObject(value) { - return isObjectLike(value) && isArrayLike(value); -} - -/** - * Performs a deep comparison between two values to determine if they are - * equivalent. - * - * **Note:** This method supports comparing arrays, array buffers, booleans, - * date objects, error objects, maps, numbers, `Object` objects, regexes, - * sets, strings, symbols, and typed arrays. `Object` objects are compared - * by their own, not inherited, enumerable properties. Functions and DOM - * nodes are **not** supported. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if the values are equivalent, else `false`. - * @example - * - * var object = { 'a': 1 }; - * var other = { 'a': 1 }; - * - * _.isEqual(object, other); - * // => true - * - * object === other; - * // => false - */ -function isEqual(value, other) { - return baseIsEqual(value, other); -} - -/** - * Checks if `value` is classified as a `Function` object. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a function, else `false`. - * @example - * - * _.isFunction(_); - * // => true - * - * _.isFunction(/abc/); - * // => false - */ -function isFunction(value) { - // The use of `Object#toString` avoids issues with the `typeof` operator - // in Safari 8-9 which returns 'object' for typed array and other constructors. - var tag = isObject(value) ? objectToString.call(value) : ''; - return tag == funcTag || tag == genTag; -} - -/** - * Checks if `value` is a valid array-like length. - * - * **Note:** This method is loosely based on - * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. - * @example - * - * _.isLength(3); - * // => true - * - * _.isLength(Number.MIN_VALUE); - * // => false - * - * _.isLength(Infinity); - * // => false - * - * _.isLength('3'); - * // => false - */ -function isLength(value) { - return typeof value == 'number' && - value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; -} - -/** - * Checks if `value` is the - * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types) - * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an object, else `false`. - * @example - * - * _.isObject({}); - * // => true - * - * _.isObject([1, 2, 3]); - * // => true - * - * _.isObject(_.noop); - * // => true - * - * _.isObject(null); - * // => false - */ -function isObject(value) { - var type = typeof value; - return !!value && (type == 'object' || type == 'function'); -} - -/** - * Checks if `value` is object-like. A value is object-like if it's not `null` - * and has a `typeof` result of "object". - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is object-like, else `false`. - * @example - * - * _.isObjectLike({}); - * // => true - * - * _.isObjectLike([1, 2, 3]); - * // => true - * - * _.isObjectLike(_.noop); - * // => false - * - * _.isObjectLike(null); - * // => false - */ -function isObjectLike(value) { - return !!value && typeof value == 'object'; -} - -/** - * Checks if `value` is classified as a typed array. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a typed array, else `false`. - * @example - * - * _.isTypedArray(new Uint8Array); - * // => true - * - * _.isTypedArray([]); - * // => false - */ -var isTypedArray = nodeIsTypedArray ? baseUnary(nodeIsTypedArray) : baseIsTypedArray; - -/** - * Creates an array of the own enumerable property names of `object`. - * - * **Note:** Non-object values are coerced to objects. See the - * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys) - * for more details. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Object - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.keys(new Foo); - * // => ['a', 'b'] (iteration order is not guaranteed) - * - * _.keys('hi'); - * // => ['0', '1'] - */ -function keys(object) { - return isArrayLike(object) ? arrayLikeKeys(object) : baseKeys(object); -} - -module.exports = isEqual; - -}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{}],5:[function(require,module,exports){ -(function (global){ -/** - * lodash (Custom Build) - * Build: `lodash modularize exports="npm" -o ./` - * Copyright jQuery Foundation and other contributors - * Released under MIT license - * Based on Underscore.js 1.8.3 - * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - */ -var reInterpolate = require('lodash._reinterpolate'), - templateSettings = require('lodash.templatesettings'); - -/** Used as references for various `Number` constants. */ -var INFINITY = 1 / 0, - MAX_SAFE_INTEGER = 9007199254740991; - -/** `Object#toString` result references. */ -var argsTag = '[object Arguments]', - errorTag = '[object Error]', - funcTag = '[object Function]', - genTag = '[object GeneratorFunction]', - symbolTag = '[object Symbol]'; - -/** Used to match empty string literals in compiled template source. */ -var reEmptyStringLeading = /\b__p \+= '';/g, - reEmptyStringMiddle = /\b(__p \+=) '' \+/g, - reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g; - -/** - * Used to match - * [ES template delimiters](http://ecma-international.org/ecma-262/7.0/#sec-template-literal-lexical-components). - */ -var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g; - -/** Used to detect unsigned integer values. */ -var reIsUint = /^(?:0|[1-9]\d*)$/; - -/** Used to ensure capturing order of template delimiters. */ -var reNoMatch = /($^)/; - -/** Used to match unescaped characters in compiled string literals. */ -var reUnescapedString = /['\n\r\u2028\u2029\\]/g; - -/** Used to escape characters for inclusion in compiled string literals. */ -var stringEscapes = { - '\\': '\\', - "'": "'", - '\n': 'n', - '\r': 'r', - '\u2028': 'u2028', - '\u2029': 'u2029' -}; - -/** Detect free variable `global` from Node.js. */ -var freeGlobal = typeof global == 'object' && global && global.Object === Object && global; - -/** Detect free variable `self`. */ -var freeSelf = typeof self == 'object' && self && self.Object === Object && self; - -/** Used as a reference to the global object. */ -var root = freeGlobal || freeSelf || Function('return this')(); - -/** - * A faster alternative to `Function#apply`, this function invokes `func` - * with the `this` binding of `thisArg` and the arguments of `args`. - * - * @private - * @param {Function} func The function to invoke. - * @param {*} thisArg The `this` binding of `func`. - * @param {Array} args The arguments to invoke `func` with. - * @returns {*} Returns the result of `func`. - */ -function apply(func, thisArg, args) { - switch (args.length) { - case 0: return func.call(thisArg); - case 1: return func.call(thisArg, args[0]); - case 2: return func.call(thisArg, args[0], args[1]); - case 3: return func.call(thisArg, args[0], args[1], args[2]); - } - return func.apply(thisArg, args); -} - -/** - * A specialized version of `_.map` for arrays without support for iteratee - * shorthands. - * - * @private - * @param {Array} [array] The array to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array} Returns the new mapped array. - */ -function arrayMap(array, iteratee) { - var index = -1, - length = array ? array.length : 0, - result = Array(length); - - while (++index < length) { - result[index] = iteratee(array[index], index, array); - } - return result; -} - -/** - * The base implementation of `_.times` without support for iteratee shorthands - * or max array length checks. - * - * @private - * @param {number} n The number of times to invoke `iteratee`. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array} Returns the array of results. - */ -function baseTimes(n, iteratee) { - var index = -1, - result = Array(n); - - while (++index < n) { - result[index] = iteratee(index); - } - return result; -} - -/** - * The base implementation of `_.values` and `_.valuesIn` which creates an - * array of `object` property values corresponding to the property names - * of `props`. - * - * @private - * @param {Object} object The object to query. - * @param {Array} props The property names to get values for. - * @returns {Object} Returns the array of property values. - */ -function baseValues(object, props) { - return arrayMap(props, function(key) { - return object[key]; - }); -} - -/** - * Used by `_.template` to escape characters for inclusion in compiled string literals. - * - * @private - * @param {string} chr The matched character to escape. - * @returns {string} Returns the escaped character. - */ -function escapeStringChar(chr) { - return '\\' + stringEscapes[chr]; -} - -/** - * Creates a unary function that invokes `func` with its argument transformed. - * - * @private - * @param {Function} func The function to wrap. - * @param {Function} transform The argument transform. - * @returns {Function} Returns the new function. - */ -function overArg(func, transform) { - return function(arg) { - return func(transform(arg)); - }; -} - -/** Used for built-in method references. */ -var objectProto = Object.prototype; - -/** Used to check objects for own properties. */ -var hasOwnProperty = objectProto.hasOwnProperty; - -/** - * Used to resolve the - * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) - * of values. - */ -var objectToString = objectProto.toString; - -/** Built-in value references. */ -var Symbol = root.Symbol, - propertyIsEnumerable = objectProto.propertyIsEnumerable; - -/* Built-in method references for those with the same name as other `lodash` methods. */ -var nativeKeys = overArg(Object.keys, Object), - nativeMax = Math.max; - -/** Used to convert symbols to primitives and strings. */ -var symbolProto = Symbol ? Symbol.prototype : undefined, - symbolToString = symbolProto ? symbolProto.toString : undefined; - -/** - * Creates an array of the enumerable property names of the array-like `value`. - * - * @private - * @param {*} value The value to query. - * @param {boolean} inherited Specify returning inherited property names. - * @returns {Array} Returns the array of property names. - */ -function arrayLikeKeys(value, inherited) { - // Safari 8.1 makes `arguments.callee` enumerable in strict mode. - // Safari 9 makes `arguments.length` enumerable in strict mode. - var result = (isArray(value) || isArguments(value)) - ? baseTimes(value.length, String) - : []; - - var length = result.length, - skipIndexes = !!length; - - for (var key in value) { - if ((inherited || hasOwnProperty.call(value, key)) && - !(skipIndexes && (key == 'length' || isIndex(key, length)))) { - result.push(key); - } - } - return result; -} - -/** - * Used by `_.defaults` to customize its `_.assignIn` use. - * - * @private - * @param {*} objValue The destination value. - * @param {*} srcValue The source value. - * @param {string} key The key of the property to assign. - * @param {Object} object The parent object of `objValue`. - * @returns {*} Returns the value to assign. - */ -function assignInDefaults(objValue, srcValue, key, object) { - if (objValue === undefined || - (eq(objValue, objectProto[key]) && !hasOwnProperty.call(object, key))) { - return srcValue; - } - return objValue; -} - -/** - * Assigns `value` to `key` of `object` if the existing value is not equivalent - * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * for equality comparisons. - * - * @private - * @param {Object} object The object to modify. - * @param {string} key The key of the property to assign. - * @param {*} value The value to assign. - */ -function assignValue(object, key, value) { - var objValue = object[key]; - if (!(hasOwnProperty.call(object, key) && eq(objValue, value)) || - (value === undefined && !(key in object))) { - object[key] = value; - } -} - -/** - * The base implementation of `_.keys` which doesn't treat sparse arrays as dense. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names. - */ -function baseKeys(object) { - if (!isPrototype(object)) { - return nativeKeys(object); - } - var result = []; - for (var key in Object(object)) { - if (hasOwnProperty.call(object, key) && key != 'constructor') { - result.push(key); - } - } - return result; -} - -/** - * The base implementation of `_.keysIn` which doesn't treat sparse arrays as dense. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names. - */ -function baseKeysIn(object) { - if (!isObject(object)) { - return nativeKeysIn(object); - } - var isProto = isPrototype(object), - result = []; - - for (var key in object) { - if (!(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) { - result.push(key); - } - } - return result; -} - -/** - * The base implementation of `_.rest` which doesn't validate or coerce arguments. - * - * @private - * @param {Function} func The function to apply a rest parameter to. - * @param {number} [start=func.length-1] The start position of the rest parameter. - * @returns {Function} Returns the new function. - */ -function baseRest(func, start) { - start = nativeMax(start === undefined ? (func.length - 1) : start, 0); - return function() { - var args = arguments, - index = -1, - length = nativeMax(args.length - start, 0), - array = Array(length); - - while (++index < length) { - array[index] = args[start + index]; - } - index = -1; - var otherArgs = Array(start + 1); - while (++index < start) { - otherArgs[index] = args[index]; - } - otherArgs[start] = array; - return apply(func, this, otherArgs); - }; -} - -/** - * The base implementation of `_.toString` which doesn't convert nullish - * values to empty strings. - * - * @private - * @param {*} value The value to process. - * @returns {string} Returns the string. - */ -function baseToString(value) { - // Exit early for strings to avoid a performance hit in some environments. - if (typeof value == 'string') { - return value; - } - if (isSymbol(value)) { - return symbolToString ? symbolToString.call(value) : ''; - } - var result = (value + ''); - return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; -} - -/** - * Copies properties of `source` to `object`. - * - * @private - * @param {Object} source The object to copy properties from. - * @param {Array} props The property identifiers to copy. - * @param {Object} [object={}] The object to copy properties to. - * @param {Function} [customizer] The function to customize copied values. - * @returns {Object} Returns `object`. - */ -function copyObject(source, props, object, customizer) { - object || (object = {}); - - var index = -1, - length = props.length; - - while (++index < length) { - var key = props[index]; - - var newValue = customizer - ? customizer(object[key], source[key], key, object, source) - : undefined; - - assignValue(object, key, newValue === undefined ? source[key] : newValue); - } - return object; -} - -/** - * Creates a function like `_.assign`. - * - * @private - * @param {Function} assigner The function to assign values. - * @returns {Function} Returns the new assigner function. - */ -function createAssigner(assigner) { - return baseRest(function(object, sources) { - var index = -1, - length = sources.length, - customizer = length > 1 ? sources[length - 1] : undefined, - guard = length > 2 ? sources[2] : undefined; - - customizer = (assigner.length > 3 && typeof customizer == 'function') - ? (length--, customizer) - : undefined; - - if (guard && isIterateeCall(sources[0], sources[1], guard)) { - customizer = length < 3 ? undefined : customizer; - length = 1; - } - object = Object(object); - while (++index < length) { - var source = sources[index]; - if (source) { - assigner(object, source, index, customizer); - } - } - return object; - }); -} - -/** - * Checks if `value` is a valid array-like index. - * - * @private - * @param {*} value The value to check. - * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index. - * @returns {boolean} Returns `true` if `value` is a valid index, else `false`. - */ -function isIndex(value, length) { - length = length == null ? MAX_SAFE_INTEGER : length; - return !!length && - (typeof value == 'number' || reIsUint.test(value)) && - (value > -1 && value % 1 == 0 && value < length); -} - -/** - * Checks if the given arguments are from an iteratee call. - * - * @private - * @param {*} value The potential iteratee value argument. - * @param {*} index The potential iteratee index or key argument. - * @param {*} object The potential iteratee object argument. - * @returns {boolean} Returns `true` if the arguments are from an iteratee call, - * else `false`. - */ -function isIterateeCall(value, index, object) { - if (!isObject(object)) { - return false; - } - var type = typeof index; - if (type == 'number' - ? (isArrayLike(object) && isIndex(index, object.length)) - : (type == 'string' && index in object) - ) { - return eq(object[index], value); - } - return false; -} - -/** - * Checks if `value` is likely a prototype object. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a prototype, else `false`. - */ -function isPrototype(value) { - var Ctor = value && value.constructor, - proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto; - - return value === proto; -} - -/** - * This function is like - * [`Object.keys`](http://ecma-international.org/ecma-262/7.0/#sec-object.keys) - * except that it includes inherited enumerable properties. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names. - */ -function nativeKeysIn(object) { - var result = []; - if (object != null) { - for (var key in Object(object)) { - result.push(key); - } - } - return result; -} - -/** - * Performs a - * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * comparison between two values to determine if they are equivalent. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if the values are equivalent, else `false`. - * @example - * - * var object = { 'a': 1 }; - * var other = { 'a': 1 }; - * - * _.eq(object, object); - * // => true - * - * _.eq(object, other); - * // => false - * - * _.eq('a', 'a'); - * // => true - * - * _.eq('a', Object('a')); - * // => false - * - * _.eq(NaN, NaN); - * // => true - */ -function eq(value, other) { - return value === other || (value !== value && other !== other); -} - -/** - * Checks if `value` is likely an `arguments` object. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an `arguments` object, - * else `false`. - * @example - * - * _.isArguments(function() { return arguments; }()); - * // => true - * - * _.isArguments([1, 2, 3]); - * // => false - */ -function isArguments(value) { - // Safari 8.1 makes `arguments.callee` enumerable in strict mode. - return isArrayLikeObject(value) && hasOwnProperty.call(value, 'callee') && - (!propertyIsEnumerable.call(value, 'callee') || objectToString.call(value) == argsTag); -} - -/** - * Checks if `value` is classified as an `Array` object. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an array, else `false`. - * @example - * - * _.isArray([1, 2, 3]); - * // => true - * - * _.isArray(document.body.children); - * // => false - * - * _.isArray('abc'); - * // => false - * - * _.isArray(_.noop); - * // => false - */ -var isArray = Array.isArray; - -/** - * Checks if `value` is array-like. A value is considered array-like if it's - * not a function and has a `value.length` that's an integer greater than or - * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is array-like, else `false`. - * @example - * - * _.isArrayLike([1, 2, 3]); - * // => true - * - * _.isArrayLike(document.body.children); - * // => true - * - * _.isArrayLike('abc'); - * // => true - * - * _.isArrayLike(_.noop); - * // => false - */ -function isArrayLike(value) { - return value != null && isLength(value.length) && !isFunction(value); -} - -/** - * This method is like `_.isArrayLike` except that it also checks if `value` - * is an object. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an array-like object, - * else `false`. - * @example - * - * _.isArrayLikeObject([1, 2, 3]); - * // => true - * - * _.isArrayLikeObject(document.body.children); - * // => true - * - * _.isArrayLikeObject('abc'); - * // => false - * - * _.isArrayLikeObject(_.noop); - * // => false - */ -function isArrayLikeObject(value) { - return isObjectLike(value) && isArrayLike(value); -} - -/** - * Checks if `value` is an `Error`, `EvalError`, `RangeError`, `ReferenceError`, - * `SyntaxError`, `TypeError`, or `URIError` object. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an error object, else `false`. - * @example - * - * _.isError(new Error); - * // => true - * - * _.isError(Error); - * // => false - */ -function isError(value) { - if (!isObjectLike(value)) { - return false; - } - return (objectToString.call(value) == errorTag) || - (typeof value.message == 'string' && typeof value.name == 'string'); -} - -/** - * Checks if `value` is classified as a `Function` object. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a function, else `false`. - * @example - * - * _.isFunction(_); - * // => true - * - * _.isFunction(/abc/); - * // => false - */ -function isFunction(value) { - // The use of `Object#toString` avoids issues with the `typeof` operator - // in Safari 8-9 which returns 'object' for typed array and other constructors. - var tag = isObject(value) ? objectToString.call(value) : ''; - return tag == funcTag || tag == genTag; -} - -/** - * Checks if `value` is a valid array-like length. - * - * **Note:** This method is loosely based on - * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. - * @example - * - * _.isLength(3); - * // => true - * - * _.isLength(Number.MIN_VALUE); - * // => false - * - * _.isLength(Infinity); - * // => false - * - * _.isLength('3'); - * // => false - */ -function isLength(value) { - return typeof value == 'number' && - value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; -} - -/** - * Checks if `value` is the - * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types) - * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an object, else `false`. - * @example - * - * _.isObject({}); - * // => true - * - * _.isObject([1, 2, 3]); - * // => true - * - * _.isObject(_.noop); - * // => true - * - * _.isObject(null); - * // => false - */ -function isObject(value) { - var type = typeof value; - return !!value && (type == 'object' || type == 'function'); -} - -/** - * Checks if `value` is object-like. A value is object-like if it's not `null` - * and has a `typeof` result of "object". - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is object-like, else `false`. - * @example - * - * _.isObjectLike({}); - * // => true - * - * _.isObjectLike([1, 2, 3]); - * // => true - * - * _.isObjectLike(_.noop); - * // => false - * - * _.isObjectLike(null); - * // => false - */ -function isObjectLike(value) { - return !!value && typeof value == 'object'; -} - -/** - * Checks if `value` is classified as a `Symbol` primitive or object. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a symbol, else `false`. - * @example - * - * _.isSymbol(Symbol.iterator); - * // => true - * - * _.isSymbol('abc'); - * // => false - */ -function isSymbol(value) { - return typeof value == 'symbol' || - (isObjectLike(value) && objectToString.call(value) == symbolTag); -} - -/** - * Converts `value` to a string. An empty string is returned for `null` - * and `undefined` values. The sign of `-0` is preserved. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to process. - * @returns {string} Returns the string. - * @example - * - * _.toString(null); - * // => '' - * - * _.toString(-0); - * // => '-0' - * - * _.toString([1, 2, 3]); - * // => '1,2,3' - */ -function toString(value) { - return value == null ? '' : baseToString(value); -} - -/** - * This method is like `_.assignIn` except that it accepts `customizer` - * which is invoked to produce the assigned values. If `customizer` returns - * `undefined`, assignment is handled by the method instead. The `customizer` - * is invoked with five arguments: (objValue, srcValue, key, object, source). - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @alias extendWith - * @category Object - * @param {Object} object The destination object. - * @param {...Object} sources The source objects. - * @param {Function} [customizer] The function to customize assigned values. - * @returns {Object} Returns `object`. - * @see _.assignWith - * @example - * - * function customizer(objValue, srcValue) { - * return _.isUndefined(objValue) ? srcValue : objValue; - * } - * - * var defaults = _.partialRight(_.assignInWith, customizer); - * - * defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 }); - * // => { 'a': 1, 'b': 2 } - */ -var assignInWith = createAssigner(function(object, source, srcIndex, customizer) { - copyObject(source, keysIn(source), object, customizer); -}); - -/** - * Creates an array of the own enumerable property names of `object`. - * - * **Note:** Non-object values are coerced to objects. See the - * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys) - * for more details. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Object - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.keys(new Foo); - * // => ['a', 'b'] (iteration order is not guaranteed) - * - * _.keys('hi'); - * // => ['0', '1'] - */ -function keys(object) { - return isArrayLike(object) ? arrayLikeKeys(object) : baseKeys(object); -} - -/** - * Creates an array of the own and inherited enumerable property names of `object`. - * - * **Note:** Non-object values are coerced to objects. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Object - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.keysIn(new Foo); - * // => ['a', 'b', 'c'] (iteration order is not guaranteed) - */ -function keysIn(object) { - return isArrayLike(object) ? arrayLikeKeys(object, true) : baseKeysIn(object); -} - -/** - * Creates a compiled template function that can interpolate data properties - * in "interpolate" delimiters, HTML-escape interpolated data properties in - * "escape" delimiters, and execute JavaScript in "evaluate" delimiters. Data - * properties may be accessed as free variables in the template. If a setting - * object is given, it takes precedence over `_.templateSettings` values. - * - * **Note:** In the development build `_.template` utilizes - * [sourceURLs](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl) - * for easier debugging. - * - * For more information on precompiling templates see - * [lodash's custom builds documentation](https://lodash.com/custom-builds). - * - * For more information on Chrome extension sandboxes see - * [Chrome's extensions documentation](https://developer.chrome.com/extensions/sandboxingEval). - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category String - * @param {string} [string=''] The template string. - * @param {Object} [options={}] The options object. - * @param {RegExp} [options.escape=_.templateSettings.escape] - * The HTML "escape" delimiter. - * @param {RegExp} [options.evaluate=_.templateSettings.evaluate] - * The "evaluate" delimiter. - * @param {Object} [options.imports=_.templateSettings.imports] - * An object to import into the template as free variables. - * @param {RegExp} [options.interpolate=_.templateSettings.interpolate] - * The "interpolate" delimiter. - * @param {string} [options.sourceURL='templateSources[n]'] - * The sourceURL of the compiled template. - * @param {string} [options.variable='obj'] - * The data object variable name. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {Function} Returns the compiled template function. - * @example - * - * // Use the "interpolate" delimiter to create a compiled template. - * var compiled = _.template('hello <%= user %>!'); - * compiled({ 'user': 'fred' }); - * // => 'hello fred!' - * - * // Use the HTML "escape" delimiter to escape data property values. - * var compiled = _.template('<%- value %>'); - * compiled({ 'value': ' - - - diff --git a/example/index.js b/example/index.js index b4adb37..75f7e39 100644 --- a/example/index.js +++ b/example/index.js @@ -1,33 +1,52 @@ 'use strict'; -/* global mapboxgl */ +var mapboxgl = require('mapbox-gl'); +var insertCss = require('insert-css'); +var fs = require('fs'); +mapboxgl.accessToken = window.localStorage.getItem('MapboxAccessToken'); -var Directions = require('../index'); +// var directionsDiv = document.body.appendChild(document.createElement('div')); +// directionsDiv.id = 'directions'; -mapboxgl.accessToken = window.localStorage.getItem('MapboxAccessToken'); +insertCss(fs.readFileSync('./src/mapbox-gl-directions.css', 'utf8')); +insertCss(fs.readFileSync('./node_modules/mapbox-gl/dist/mapbox-gl.css', 'utf8')); +var mapDiv = document.body.appendChild(document.createElement('div')); +mapDiv.style = 'position:absolute;top:0;right:0;left:0;bottom:0;'; -var map = new mapboxgl.Map({ +var map = window.map = new mapboxgl.Map({ hash: true, - container: 'map', + container: mapDiv, style: 'mapbox://styles/mapbox/streets-v9', center: [-79.4512, 43.6568], zoom: 13 }); -var directions = new mapboxgl.Directions({ +// remove control +var button = document.body.appendChild(document.createElement('button')); +button.style = 'z-index:10;position:absolute;top:10px;right:10px;'; +button.textContent = 'Remove directions control'; + +// remove all waypoints +var removeWaypointsButton = document.body.appendChild(document.createElement('button')); +removeWaypointsButton.style = 'z-index:10;position:absolute;top:30px;right:10px;'; +removeWaypointsButton.textContent = 'Remove all waypoints'; + +// directions +var MapboxDirections = require('../src/index'); +var directions = new MapboxDirections({ + accessToken: window.localStorage.getItem('MapboxAccessToken'), unit: 'metric', - profile: 'cycling', - container: 'directions' + profile: 'cycling' }); +window.directions = directions; -var button = document.createElement('button'); -button.textContent = 'click me'; - -map.getContainer().querySelector('.mapboxgl-ctrl-bottom-left').appendChild(button); -map.addControl(directions); +map.addControl(directions, 'top-left'); map.on('load', () => { button.addEventListener('click', function() { - directions.setOrigin([-79.4512, 43.6568]); - directions.setDestination('Montreal Quebec'); + map.removeControl(directions); }); -}); + + removeWaypointsButton.addEventListener('click', function() { + directions.removeRoutes(); + }); +}); \ No newline at end of file diff --git a/package.json b/package.json index 717abcc..9ced6de 100644 --- a/package.json +++ b/package.json @@ -2,20 +2,23 @@ "name": "mapbox-gl-directions", "version": "2.2.0", "description": "A mapboxgl plugin for the Mapbox Directions API", - "main": "dist/mapbox-gl-directions.js", + "main": "./src/index.js", "browserify": { "transform": [ "babelify", "brfs" ] }, + "peerDependencies": { + "mapbox-gl": "^0.27.0 || ^0.28.0" + }, "scripts": { "prepublish": "npm run build", "start": "NODE_ENV=development budo example/index.js:example/bundle.js --live", - "build": "NODE_ENV=production browserify -s mapboxDirections index.js > dist/mapbox-gl-directions.js", + "build": "NODE_ENV=production mkdir -p dist && browserify -s MapboxDirections src/index.js > dist/mapbox-gl-directions.js && cp src/mapbox-gl-directions.css dist/ && cp -r src/icons/ dist/", "test": "NODE_ENV=test npm run lint && browserify test/index.js | smokestack -b firefox | tap-status", "docs": "documentation build --format=md > API.md", - "lint": "eslint --no-eslintrc -c .eslintrc index.js src" + "lint": "eslint --no-eslintrc -c .eslintrc src" }, "repository": { "type": "git", @@ -45,9 +48,10 @@ "budo": "^8.3.0", "documentation": "^4.0.0-beta5", "eslint": "^2.13.1", + "insert-css": "^2.0.0", "json-loader": "0.5.4", "lodash.once": "^4.0.0", - "mapbox-gl": "^0.22.1", + "mapbox-gl": "^0.27.0", "smokestack": "^3.3.1", "tap-status": "^1.0.1", "tape": "^4.6.0", diff --git a/src/actions/index.js b/src/actions/index.js index f55f960..639e8c8 100644 --- a/src/actions/index.js +++ b/src/actions/index.js @@ -61,9 +61,7 @@ function fetchDirections() { options.push('instructions=text'); options.push('alternatives=true'); options.push('steps=true'); - - var token = accessToken ? accessToken : mapboxgl.accessToken; - options.push('access_token=' + token); + options.push('access_token=' + accessToken); request.abort(); request.open('GET', `${api}mapbox.${profile}/${query}.json?${options.join('&')}`, true); diff --git a/src/controls/geocoder.js b/src/controls/geocoder.js index 5adfa4e..62862d1 100644 --- a/src/controls/geocoder.js +++ b/src/controls/geocoder.js @@ -1,33 +1,17 @@ 'use strict'; -var Typeahead = require('suggestions'); -var debounce = require('lodash.debounce'); -var extend = require('xtend'); -var EventEmitter = require('events').EventEmitter; +import Typeahead from 'suggestions'; +import debounce from 'lodash.debounce'; +import extend from 'xtend'; +import { EventEmitter } from 'events'; +import utils from '../utils' // Mapbox Geocoder version var API = 'https://api.mapbox.com/geocoding/v5/mapbox.places/'; -/** - * A geocoder component using Mapbox Geocoding API - * @class mapboxgl.Geocoder - * - * @param {Object} options - * @param {String} [options.position="top-right"] A string indicating the control's position on the map. Options are `top-right`, `top-left`, `bottom-right`, `bottom-left` - * @param {String} [options.accessToken=null] Required unless `mapboxgl.accessToken` is set globally - * @param {string|element} options.container The HTML element to append the Geocoder input to. if container is not specified, `map.getcontainer()` is used. - * @param {Array} options.proximity If set, search results closer to these coordinates will be given higher priority. - * @param {Array} options.bbox Limit results to a given bounding box provided as `[minX, minY, maxX, maxY]`. - * @param {Number} [options.zoom=16] On geocoded result what zoom level should the map animate to. - * @param {Boolean} [options.flyTo=true] If false, animating the map to a selected result is disabled. - * @param {String} [options.placeholder="Search"] Override the default placeholder attribute value. - * @param {string} options.types a comma seperated list of types that filter results to match those specified. See https://www.mapbox.com/developers/api/geocoding/#filter-type for available types. - * @param {string} options.country a comma seperated list of country codes to limit results to specified country or countries. - * @example - * var geocoder = new mapboxgl.Geocoder(); - * map.addControl(geocoder); - * @return {Geocoder} `this` - */ +// Geocoder - this slightly mimicks the mapboxl-gl-geocoder but isn't an exact replica. +// Once gl-js plugins can be added to custom divs, we should be able to require mapbox-gl-geocoder +// instead of including it here function Geocoder(options) { this._ev = new EventEmitter(); this.options = extend({}, this.options, options); @@ -36,37 +20,15 @@ function Geocoder(options) { Geocoder.prototype = { options: { - position: 'top-left', placeholder: 'Search', zoom: 16, flyTo: true }, - addTo: function (map) { - this._map = map; - var container = this._container = this.onAdd(map); - if (this.options && this.options.position) { - var pos = this.options.position; - var corner = map._controlCorners[pos]; - container.className += ' mapboxgl-ctrl'; - if (pos.indexOf('bottom') !== -1) { - corner.insertBefore(container, corner.firstChild); - } else { - corner.appendChild(container); - } - } - - return this; - }, - onAdd: function(map) { - this.request = new XMLHttpRequest(); + this._map = map; - this.container = this.options.container ? - typeof this.options.container === 'string' ? - document.getElementById(this.options.container) : - this.options.container : - map.getContainer(); + this.request = new XMLHttpRequest(); // Template var el = document.createElement('div'); @@ -126,8 +88,6 @@ Geocoder.prototype = { el.appendChild(input); el.appendChild(actions); - this.container.appendChild(el); - // Override the control being added to control containers if (this.options.container) this.options.position = false; @@ -199,8 +159,8 @@ Geocoder.prototype = { if (!input) return; if (typeof input === 'object' && input.length) { input = [ - mapboxgl.util.wrap(input[0], -180, 180), - mapboxgl.util.wrap(input[1], -180, 180) + utils.wrap(input[0]), + utils.wrap(input[1]) ].join(); } @@ -218,8 +178,8 @@ Geocoder.prototype = { if (!input) return; if (typeof input === 'object' && input.length) { input = [ - mapboxgl.util.wrap(input[0], -180, 180), - mapboxgl.util.wrap(input[1], -180, 180) + utils.wrap(input[0]), + utils.wrap(input[1]) ].join(); } diff --git a/src/controls/inputs.js b/src/controls/inputs.js index ba6aa0e..b1d4066 100644 --- a/src/controls/inputs.js +++ b/src/controls/inputs.js @@ -63,23 +63,27 @@ export default class Inputs { reverse } = this.actions; - const { geocoder } = this.store.getState(); + const { geocoder, accessToken } = this.store.getState(); this.originInput = new Geocoder(Object.assign({}, { flyTo: false, placeholder: 'Choose a starting place', - container: this.container.querySelector('#mapbox-directions-origin-input') + accessToken: accessToken }, geocoder)); - this._map.addControl(this.originInput); + var originEl = this.originInput.onAdd(); + var originContainerEl = this.container.querySelector('#mapbox-directions-origin-input'); + originContainerEl.appendChild(originEl); this.destinationInput = new Geocoder(Object.assign({}, { flyTo: false, placeholder: 'Choose destination', - container: this.container.querySelector('#mapbox-directions-destination-input') + accessToken: accessToken }, geocoder)); - this._map.addControl(this.destinationInput); + var destinationEl = this.destinationInput.onAdd(); + this.container.querySelector('#mapbox-directions-destination-input').appendChild(destinationEl); + this.originInput.on('result', (e) => { const coords = e.result.center; diff --git a/src/directions.js b/src/directions.js index 14a6a3d..b0dd44e 100644 --- a/src/directions.js +++ b/src/directions.js @@ -15,11 +15,12 @@ import directionsStyle from './directions_style'; import Inputs from './controls/inputs'; import Instructions from './controls/instructions'; -export default class Directions { +export default class MapboxDirections { constructor(options) { this.actions = bindActionCreators(actions, store.dispatch); this.actions.setOptions(options || {}); + this.options = options || {}; this.onDragDown = this._onDragDown.bind(this); this.onDragMove = this._onDragMove.bind(this); @@ -28,30 +29,13 @@ export default class Directions { this.onClick = this._onClick.bind(this); } - addTo(map) { - this._map = map; - var container = this._container = this.onAdd(map); - if (this.options && this.options.position) { - var pos = this.options.position; - var corner = map._controlCorners[pos]; - container.className += ' mapboxgl-ctrl'; - if (pos.indexOf('bottom') !== -1) { - corner.insertBefore(container, corner.firstChild); - } else { - corner.appendChild(container); - } - } - - return this; - } - onAdd(map) { this._map = map; - const { container, controls } = store.getState(); + const { controls } = store.getState(); - this.container = container ? typeof container === 'string' ? - document.getElementById(container) : container : this._map.getContainer(); + var el = this.container = document.createElement('div'); + el.className = 'mapboxgl-ctrl-directions mapboxgl-ctrl'; // Add controls to the page const inputEl = document.createElement('div'); @@ -66,23 +50,32 @@ export default class Directions { setRouteIndex: this.actions.setRouteIndex }, this._map); - if (controls.inputs) this.container.appendChild(inputEl); - if (controls.instructions) this.container.appendChild(directionsEl); + if (controls.inputs) el.appendChild(inputEl); + el.appendChild(directionsEl); this.subscribedActions(); if (this._map.loaded()) this.mapState() else this._map.on('load', () => this.mapState()); + + return el; } /** - * Removes the control from the map it has been added to. + * Removes the control from the map it has been added to. This is called by `map.removeControl`, + * which is the recommended method to remove controls. * * @returns {Control} `this` */ - remove() { - this.container.parentNode.removeChild(this.container); - this._map = null; - return this; + onRemove(map) { + this.container.parentNode.removeChild(this.container); + this.removeRoutes(); + map.off('mousedown', this.onDragDown); + map.off('mousemove', this.move); + map.off('touchstart', this.onDragDown); + map.off('touchstart', this.move); + map.off('click', this.onClick); + this._map = null; + return this; } mapState() { @@ -316,7 +309,7 @@ export default class Directions { /** * Turn on or off interactivity * @param {Boolean} state sets interactivity based on a state of `true` or `false`. - * @returns {Directions} this + * @returns {MapboxDirections} this */ interactive(state) { if (state) { @@ -350,7 +343,7 @@ export default class Directions { * Sets origin. _Note:_ calling this method requires the [map load event](https://www.mapbox.com/mapbox-gl-js/api/#Map.load) * to have run. * @param {Array|String} query An array of coordinates [lng, lat] or location name as a string. - * @returns {Directions} this + * @returns {MapboxDirections} this */ setOrigin(query) { if (typeof query === 'string') { @@ -374,7 +367,7 @@ export default class Directions { * Sets destination. _Note:_ calling this method requires the [map load event](https://www.mapbox.com/mapbox-gl-js/api/#Map.load) * to have run. * @param {Array|String} query An array of coordinates [lng, lat] or location name as a string. - * @returns {Directions} this + * @returns {MapboxDirections} this */ setDestination(query) { if (typeof query === 'string') { @@ -388,7 +381,7 @@ export default class Directions { /** * Swap the origin and destination. - * @returns {Directions} this + * @returns {MapboxDirections} this */ reverse() { this.actions.reverse(); @@ -400,7 +393,7 @@ export default class Directions { * [map load event](https://www.mapbox.com/mapbox-gl-js/api/#Map.load) to have run. * @param {Number} index position waypoint should be placed in the waypoint array * @param {Array|Point} waypoint can be a GeoJSON Point Feature or [lng, lat] coordinates. - * @returns {Directions} this; + * @returns {MapboxDirections} this; */ addWaypoint(index, waypoint) { if (!waypoint.type) waypoint = utils.createPoint(waypoint, { id: 'waypoint' }); @@ -414,7 +407,7 @@ export default class Directions { * to have run. * @param {Number} index indexed position of the waypoint to update * @param {Array|Point} waypoint can be a GeoJSON Point Feature or [lng, lat] coordinates. - * @returns {Directions} this; + * @returns {MapboxDirections} this; */ setWaypoint(index, waypoint) { if (!waypoint.type) waypoint = utils.createPoint(waypoint, { id: 'waypoint' }); @@ -425,7 +418,7 @@ export default class Directions { /** * Remove a waypoint from the route. * @param {Number} index position in the waypoints array. - * @returns {Directions} this; + * @returns {MapboxDirections} this; */ removeWaypoint(index) { const { waypoints } = store.getState(); @@ -441,6 +434,17 @@ export default class Directions { return store.getState().waypoints; } + /** + * Removes all routes and waypoints from the map. + * + * @returns {MapboxDirections} this; + */ + removeRoutes() { + this.actions.clearOrigin(); + this.actions.clearDestination(); + return this; + } + /** * Subscribe to events that happen within the plugin. * @param {String} type name of event. Available events and the data passed into their respective event objects are: @@ -453,7 +457,7 @@ export default class Directions { * - __route__ `{ route } Fired when a route is updated` * - __error__ `{ error } Error as string * @param {Function} fn function that's called when the event is emitted. - * @returns {Directions} this; + * @returns {MapboxDirections} this; */ on(type, fn) { this.actions.eventSubscribe(type, fn); diff --git a/dist/icons/arrive.svg b/src/icons/arrive.svg similarity index 100% rename from dist/icons/arrive.svg rename to src/icons/arrive.svg diff --git a/dist/icons/bear-left.svg b/src/icons/bear-left.svg similarity index 100% rename from dist/icons/bear-left.svg rename to src/icons/bear-left.svg diff --git a/dist/icons/bear-right.svg b/src/icons/bear-right.svg similarity index 100% rename from dist/icons/bear-right.svg rename to src/icons/bear-right.svg diff --git a/dist/icons/continue.svg b/src/icons/continue.svg similarity index 100% rename from dist/icons/continue.svg rename to src/icons/continue.svg diff --git a/dist/icons/depart.svg b/src/icons/depart.svg similarity index 100% rename from dist/icons/depart.svg rename to src/icons/depart.svg diff --git a/dist/icons/enter-roundabout.svg b/src/icons/enter-roundabout.svg similarity index 100% rename from dist/icons/enter-roundabout.svg rename to src/icons/enter-roundabout.svg diff --git a/dist/icons/error.svg b/src/icons/error.svg similarity index 100% rename from dist/icons/error.svg rename to src/icons/error.svg diff --git a/dist/icons/reverse.svg b/src/icons/reverse.svg similarity index 100% rename from dist/icons/reverse.svg rename to src/icons/reverse.svg diff --git a/dist/icons/sharp-left.svg b/src/icons/sharp-left.svg similarity index 100% rename from dist/icons/sharp-left.svg rename to src/icons/sharp-left.svg diff --git a/dist/icons/sharp-right.svg b/src/icons/sharp-right.svg similarity index 100% rename from dist/icons/sharp-right.svg rename to src/icons/sharp-right.svg diff --git a/dist/icons/turn-left.svg b/src/icons/turn-left.svg similarity index 100% rename from dist/icons/turn-left.svg rename to src/icons/turn-left.svg diff --git a/dist/icons/turn-right.svg b/src/icons/turn-right.svg similarity index 100% rename from dist/icons/turn-right.svg rename to src/icons/turn-right.svg diff --git a/dist/icons/u-turn.svg b/src/icons/u-turn.svg similarity index 100% rename from dist/icons/u-turn.svg rename to src/icons/u-turn.svg diff --git a/dist/icons/waypoint.svg b/src/icons/waypoint.svg similarity index 100% rename from dist/icons/waypoint.svg rename to src/icons/waypoint.svg diff --git a/index.js b/src/index.js similarity index 69% rename from index.js rename to src/index.js index a4ffc7a..1441184 100644 --- a/index.js +++ b/src/index.js @@ -1,6 +1,6 @@ /** - * A directions component using Mapbox Directions APi - * @class mapboxgl.Directions + * A directions component using Mapbox Directions API + * @class MapboxDirections * * @param {Object} options * @param {Array} [options.styles] Override default layer properties of the [directions source](https://github.com/mapbox/mapbox-gl-directions/blob/master/src/directions_style.js). Documentation for each property are specified in the [Mapbox GL Style Reference](https://www.mapbox.com/mapbox-gl-style-spec/). @@ -8,25 +8,22 @@ * @param {Boolean} [options.interactive=true] Enable/Disable mouse or touch interactivity from the plugin * @param {String} [options.profile="driving"] Routing profile to use. Options: `driving`, `walking`, `cycling` * @param {String} [options.unit="imperial"] Measurement system to be used in navigation instructions. Options: `imperial`, `metric` - * @param {string|Element} options.container HTML element to initialize the map in (or element id as string). If no container is passed map.getContainer() is used instead. * @param {Object} [options.geocoder] Pass options available to mapbox-gl-geocoder as [documented here](https://github.com/mapbox/mapbox-gl-geocoder/blob/master/API.md#mapboxglgeocoder). * @param {Object} [options.controls] * @param {Boolean} [options.controls.inputs=true] Hide or display the inputs control. * @param {Boolean} [options.controls.instructions=true] Hide or display the instructions control. * @example - * var directions = new mapboxgl.Directions({ - * container: 'directions', + * var MapboxDirections = require('../src/index'); + * var directions = new MapboxDirections({ + * accessToken: 'YOUR-MAPBOX-ACCESS-TOKEN', * unit: 'metric', - * profile: 'walking' + * profile: 'cycling' * }); - * + * // add to your mapboxgl map * map.addControl(directions); - * @return {Directions} `this` + * + * @return {MapboxDirections} `this` */ -import Directions from './src/directions'; +import MapboxDirections from './directions'; -if (window.mapboxgl) { - mapboxgl.Directions = Directions; -} else if (typeof module !== 'undefined') { - module.exports = Directions; -} +module.exports = MapboxDirections; \ No newline at end of file diff --git a/dist/mapbox-gl-directions.css b/src/mapbox-gl-directions.css similarity index 97% rename from dist/mapbox-gl-directions.css rename to src/mapbox-gl-directions.css index 33262e3..35e64d1 100644 --- a/dist/mapbox-gl-directions.css +++ b/src/mapbox-gl-directions.css @@ -141,6 +141,14 @@ } /* Basics */ +.mapboxgl-ctrl-directions { + width: 33.33333%; + min-width: 250px; + max-width: 300px; +} +.mapbox-directions-component { + position: relative; +} .mapbox-directions-component, .mapbox-directions-component *, .mapbox-directions-component *:after, @@ -160,14 +168,12 @@ /* Layout containers */ .directions-control { - position:absolute; - width:33.3333%; - max-width:300px; - min-width:200px; + width:100%; z-index:1; } .directions-control.directions-control-directions { background:rgba(0,0,0,0.75); + margin: 7px 0 0; color:#fff; top:0; right:0; @@ -178,7 +184,6 @@ .directions-control.directions-control-inputs { top:10px; left:10px; - max-width:360px; } /* Inputs */ @@ -210,7 +215,7 @@ position:absolute; z-index:10; background:white; - left:50px; + left:40px; top:30px; cursor:pointer; } @@ -295,18 +300,16 @@ /* Route Summary */ .mapbox-directions-route-summary { - position:fixed; + position: relative; z-index:1; width:100%; - min-height:50px; background-color:rgba(0,0,0,0.75); color:#fff; - padding:10px 20px; - font-size:20px; + padding:5px 10px; + font-size:15px; line-height:28px; } .mapbox-directions-route-summary + .mapbox-directions-instructions { - padding-top:50px; } .mapbox-directions-route-summary h1 { font-weight:500; @@ -321,15 +324,16 @@ } /* Alt route selection */ - .mapbox-directions-multiple { - min-height:75px; + .mapbox-directions-instructions { + overflow: scroll; } - .mapbox-directions-multiple + .mapbox-directions-instructions { - padding-top:75px; + .mapbox-directions-instructions-wrapper { + max-height: 50vh; } .mapbox-directions-routes { - margin:0 0 10px; + margin-left: 5px; font-size:12px; + float: right; } .mapbox-directions-routes input[type=radio] { display: none;} .mapbox-directions-routes input[type=radio]:not(:checked) + .button:before { width: 0;} @@ -347,8 +351,8 @@ /* Instructions */ .mapbox-directions-instructions .directions-icon { position:absolute; - left:10px; - top:25px; + left:12px; + top:20px; margin:auto; } .mapbox-directions-instructions .directions-icon:before { @@ -366,7 +370,7 @@ padding:5px 10px; font-size:12px; left:30px; - bottom:-15px; + bottom:-10px; } .mapbox-directions-steps { position:relative; @@ -379,8 +383,10 @@ color:rgba(255,255,255,.75); cursor:pointer; padding:20px 20px 20px 40px; - font-size:20px; - line-height:25px; + font-size:14px; + line-height:18px; + font-weight: 300; + letter-spacing:0.1em; } .mapbox-directions-step * { pointer-events:none; } .mapbox-directions-step:hover { @@ -389,8 +395,8 @@ .mapbox-directions-step:after { content:''; position:absolute; - top:50px; - bottom:-20px; + top:45px; + bottom:-10px; border-left:2px dotted rgba(255,255,255,.2); left:20px; } @@ -431,7 +437,7 @@ .mapbox-directions-routes { float:right; margin-right:10px; } .directions-control.directions-control-directions { top:auto; max-height:40%; } .mapbox-directions-multiple { min-height:50px; } -.mapbox-directions-multiple + .mapbox-directions-instructions { padding-top:50px; } + } @-webkit-keyframes rotate { from { -webkit-transform: rotate(0deg); } to { -webkit-transform: rotate(360deg); } } diff --git a/src/templates/instructions.html b/src/templates/instructions.html index 2daeada..1ac7bc7 100644 --- a/src/templates/instructions.html +++ b/src/templates/instructions.html @@ -13,29 +13,31 @@

<%- duration %>

-
    - <% steps.forEach(function(step) { %> - <% - var distance = step.distance ? format(step.distance) : false; - var icon = step.maneuver.type.replace(/\s+/g, '-').toLowerCase(); - var lng = step.maneuver.location.coordinates[0]; - var lat = step.maneuver.location.coordinates[1]; - %> -
  1. - -
    - <%= step.maneuver.instruction %> -
    - <% if (step.distance) { %> -
    - <%= distance %> +
    +
      + <% steps.forEach(function(step) { %> + <% + var distance = step.distance ? format(step.distance) : false; + var icon = step.maneuver.type.replace(/\s+/g, '-').toLowerCase(); + var lng = step.maneuver.location.coordinates[0]; + var lat = step.maneuver.location.coordinates[1]; + %> +
    1. + +
      + <%= step.maneuver.instruction %>
      - <% } %> -
    2. - <% }); %> -
    + <% if (step.distance) { %> +
    + <%= distance %> +
    + <% } %> +
  2. + <% }); %> +
+
diff --git a/test/index.js b/test/index.js index f0a0c4c..e790dcd 100644 --- a/test/index.js +++ b/test/index.js @@ -2,7 +2,7 @@ const test = require('tape'); window.mapboxgl = require('mapbox-gl'); -require('../index'); +require('../src/index'); mapboxgl.accessToken = process.env.MapboxAccessToken; diff --git a/test/test.directions.js b/test/test.directions.js index 8dc8a15..cf99f7e 100644 --- a/test/test.directions.js +++ b/test/test.directions.js @@ -9,7 +9,8 @@ test('directions', (tt) => { function setup(opts) { container = document.createElement('div'); map = new mapboxgl.Map({ container: container }); - directions = new mapboxgl.Directions(opts); + const MapboxDirections = require('..'); + directions = new MapboxDirections(opts); map.addControl(directions); } diff --git a/test/test.inputs.js b/test/test.inputs.js index 154d852..ff6dde7 100644 --- a/test/test.inputs.js +++ b/test/test.inputs.js @@ -15,7 +15,8 @@ test('Directions#inputControl', tt => { function setup(opts) { container = document.createElement('div'); map = new mapboxgl.Map({ container: container }); - directions = new mapboxgl.Directions(opts); + var MapboxDirections = require('..'); + directions = new MapboxDirections(opts); map.addControl(directions); } diff --git a/test/test.instructions.js b/test/test.instructions.js index 90413aa..f230416 100644 --- a/test/test.instructions.js +++ b/test/test.instructions.js @@ -9,7 +9,8 @@ test('Directions#instructionControl', tt => { function setup(opts) { container = document.createElement('div'); map = new mapboxgl.Map({ container: container }); - directions = new mapboxgl.Directions(opts); + var MapboxDirections = require('..'); + directions = new MapboxDirections(opts); map.addControl(directions); } diff --git a/test/test.options.js b/test/test.options.js index d34194e..3c5c9c1 100644 --- a/test/test.options.js +++ b/test/test.options.js @@ -9,7 +9,8 @@ test('Directions#option', tt => { function setup(opts) { container = document.createElement('div'); map = new mapboxgl.Map({ container: container }); - directions = new mapboxgl.Directions(opts); + var MapboxDirections = require('..'); + directions = new MapboxDirections(opts); map.addControl(directions); }