UNPKG

mapbox

Version:
272 lines (241 loc) 11.6 kB
'use strict'; var invariant = require('../../vendor/invariant'); var makeService = require('../make_service'); /** * @class MapboxGeocoding */ var MapboxGeocoding = makeService('MapboxGeocoding'); var API_GEOCODING_FORWARD = '/geocoding/v5/{dataset}/{query}.json{?access_token,proximity,country,types,bbox,limit,autocomplete,language}'; var API_GEOCODING_REVERSE = '/geocoding/v5/{dataset}/{longitude},{latitude}.json{?access_token,types,limit,language}'; var REVERSE_GEOCODING_PRECISION = 5; var FORWARD_GEOCODING_PROXIMITY_PRECISION = 3; function roundTo(value, places) { var mult = Math.pow(10, places); return Math.round(value * mult) / mult; } /** * Search for a location with a string, using the * [Mapbox Geocoding API](https://www.mapbox.com/api-documentation/#geocoding). * * The `query` parmeter can be an array of strings only if batch geocoding * is used by specifying `mapbox.places-permanent` as the `dataset` option. * * @param {string|Array<string>} query desired location * @param {Object} [options={}] additional options meant to tune * the request * @param {Object} options.proximity a proximity argument: this is * a geographical point given as an object with latitude and longitude * properties. Search results closer to this point will be given * higher priority. * @param {Array} options.bbox a bounding box argument: this is * a bounding box given as an array in the format [minX, minY, maxX, maxY]. * Search results will be limited to the bounding box. * @param {Array<string>|string} options.language Specify the language to use for response text and, for forward geocoding, query result weighting. Options are IETF language tags comprised of a mandatory ISO 639-1 language code and optionally one or more IETF subtags for country or script. More than one value can also be specified, as an array or separated by commas. * @param {Array<string>|string} options.types an array or 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 {number} [options.limit=5] is the maximum number of results to return, between 1 and 10 inclusive. * Some very specific queries may return fewer results than the limit. * @param {Array<string>|string} options.country an array or comma separated list of country codes to * limit results to specified country or countries. * @param {boolean} [options.autocomplete=true] whether to include results that include * the query only as a prefix. This is useful for UIs where users type * values, but if you have complete addresses as input, you'll want to turn it off * @param {string} [options.dataset=mapbox.places] the desired data to be * geocoded against. The default, mapbox.places, does not permit unlimited * caching. `mapbox.places-permanent` is available on request and does * permit permanent caching. * @param {Function} callback called with (err, results) * @returns {Promise} response * @example * var mapboxClient = new MapboxClient('ACCESSTOKEN'); * mapboxClient.geocodeForward('Paris, France', function(err, res) { * // res is a GeoJSON document with geocoding matches * }); * // using the proximity option to weight results closer to texas * mapboxClient.geocodeForward('Paris, France', { * proximity: { latitude: 33.6875431, longitude: -95.4431142 } * }, function(err, res) { * // res is a GeoJSON document with geocoding matches * }); * // using the bbox option to limit results to a portion of Washington, D.C. * mapboxClient.geocodeForward('Starbucks', { * bbox: [-77.083056,38.908611,-76.997778,38.959167] * }, function(err, res) { * // res is a GeoJSON document with geocoding matches * }); */ MapboxGeocoding.prototype.geocodeForward = function(query, options, callback) { // permit the options argument to be omitted, or the options + callback args to be omitted if using promise syntax if (callback === undefined && (options === undefined || typeof options === 'function')) { callback = options; options = {}; } // typecheck arguments if (Array.isArray(query)) { if (options.dataset !== 'mapbox.places-permanent') { throw new Error('Batch geocoding is only available with the mapbox.places-permanent endpoint. See https://mapbox.com/api-documentation/#batch-requests for details'); } else { query = query.join(';'); } } invariant(typeof query === 'string', 'query must be a string'); invariant(typeof options === 'object', 'options must be an object'); var queryOptions = { query: query, dataset: 'mapbox.places' }; var precision = FORWARD_GEOCODING_PROXIMITY_PRECISION; if (options.precision) { invariant(typeof options.precision === 'number', 'precision option must be number'); precision = options.precision; } if (options.proximity) { invariant(typeof options.proximity.latitude === 'number' && typeof options.proximity.longitude === 'number', 'proximity must be an object with numeric latitude & longitude properties'); queryOptions.proximity = roundTo(options.proximity.longitude, precision) + ',' + roundTo(options.proximity.latitude, precision); } if (options.bbox) { invariant(typeof options.bbox[0] === 'number' && typeof options.bbox[1] === 'number' && typeof options.bbox[2] === 'number' && typeof options.bbox[3] === 'number' && options.bbox.length === 4, 'bbox must be an array with numeric values in the form [minX, minY, maxX, maxY]'); queryOptions.bbox = options.bbox[0] + ',' + options.bbox[1] + ',' + options.bbox[2] + ',' + options.bbox[3]; } if (options.limit) { invariant(typeof options.limit === 'number', 'limit must be a number'); queryOptions.limit = options.limit; } if (options.dataset) { invariant(typeof options.dataset === 'string', 'dataset option must be string'); queryOptions.dataset = options.dataset; } if (options.country) { if (Array.isArray(options.country)) { queryOptions.country = options.country.join(','); } else { invariant(typeof options.country === 'string', 'country option must be an array or string'); queryOptions.country = options.country; } } if (options.language) { if (Array.isArray(options.language)) { queryOptions.language = options.language.join(','); } else { invariant(typeof options.language === 'string', 'language option must be an array or string'); queryOptions.language = options.language; } } if (options.types) { if (Array.isArray(options.types)) { queryOptions.types = options.types.join(','); } else { invariant(typeof options.types === 'string', 'types option must be an array or string'); queryOptions.types = options.types; } } if (typeof options.autocomplete === 'boolean') { invariant(typeof options.autocomplete === 'boolean', 'autocomplete must be a boolean'); queryOptions.autocomplete = options.autocomplete; } return this.client({ path: API_GEOCODING_FORWARD, params: queryOptions, callback: callback }); }; /** * Given a location, determine what geographical features are located * there. This uses the [Mapbox Geocoding API](https://www.mapbox.com/api-documentation/#geocoding). * * @param {Object} location the geographical point to search * @param {number} location.latitude decimal degrees latitude, in range -90 to 90 * @param {number} location.longitude decimal degrees longitude, in range -180 to 180 * @param {Object} [options={}] additional options meant to tune * the request. * @param {Array<string>|string} options.language Specify the language to use for response text and, for forward geocoding, query result weighting. Options are IETF language tags comprised of a mandatory ISO 639-1 language code and optionally one or more IETF subtags for country or script. More than one value can also be specified, separated by commas or as an array. * @param {Array<string>|string} options.types an array or comma seperated list of types that filter * results to match those specified. See * https://www.mapbox.com/api-documentation/#retrieve-places-near-a-location * for available types. * @param {number} [options.limit=1] is the maximum number of results to return, between 1 and 5 * inclusive. Requires a single options.types to be specified (see example). * @param {string} [options.dataset=mapbox.places] the desired data to be * geocoded against. The default, mapbox.places, does not permit unlimited * caching. `mapbox.places-permanent` is available on request and does * permit permanent caching. * @param {Function} callback called with (err, results) * @returns {Promise} response * @example * var mapboxClient = new MapboxClient('ACCESSTOKEN'); * mapboxClient.geocodeReverse( * { latitude: 33.6875431, longitude: -95.4431142 }, * function(err, res) { * // res is a GeoJSON document with geocoding matches * }); * @example * var mapboxClient = new MapboxClient('ACCESSTOKEN'); * mapboxClient.geocodeReverse( * { latitude: 33.6875431, longitude: -95.4431142, options: { types: 'address', limit: 3 } }, * function(err, res) { * // res is a GeoJSON document with up to 3 geocoding matches * }); */ MapboxGeocoding.prototype.geocodeReverse = function(location, options, callback) { // permit the options argument to be omitted, or the options + callback args to be omitted if using promise syntax if (callback === undefined && (options === undefined || typeof options === 'function')) { callback = options; options = {}; } // typecheck arguments invariant((typeof location === 'object' && location !== null), 'location must be an object'); invariant(typeof options === 'object', 'options must be an object'); invariant(typeof location.latitude === 'number' && typeof location.longitude === 'number', 'location must be an object with numeric latitude & longitude properties'); var queryOptions = { dataset: 'mapbox.places' }; if (options.dataset) { invariant(typeof options.dataset === 'string', 'dataset option must be string'); queryOptions.dataset = options.dataset; } var precision = REVERSE_GEOCODING_PRECISION; if (options.precision) { invariant(typeof options.precision === 'number', 'precision option must be number'); precision = options.precision; } if (options.language) { if (Array.isArray(options.language)) { queryOptions.language = options.language.join(','); } else { invariant(typeof options.language === 'string', 'language option must be an array or string'); queryOptions.language = options.language; } } if (options.types) { if (Array.isArray(options.types)) { queryOptions.types = options.types.join(','); } else { invariant(typeof options.types === 'string', 'types option must be an array or string'); queryOptions.types = options.types; } } if (options.limit) { invariant(typeof options.limit === 'number', 'limit option must be a number'); invariant(options.types.split(',').length === 1, 'a single type must be specified to use the limit option'); queryOptions.limit = options.limit; } queryOptions.longitude = roundTo(location.longitude, precision); queryOptions.latitude = roundTo(location.latitude, precision); return this.client({ path: API_GEOCODING_REVERSE, params: queryOptions, callback: callback }); }; module.exports = MapboxGeocoding;