UNPKG

geocoder-arcgis

Version:

JavaScript wrapper for the ESRI ArcGIS geocoder

381 lines (320 loc) 11.3 kB
'use strict'; var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } var FormData = require('form-data'); var get = require('lodash.get'); var isString = require('lodash.isstring'); var isObject = require('lodash.isobject'); var ArcGISAuth = require('./auth.js'); require('es6-promise').polyfill(); require('fetch-everywhere'); /** * Promises based node.js wrapper for the ESRI ArcGIS geocoder * * @param options Add client_id, client_secret to get token from ArcGIS auth * @return Instance of {@link GeocoderArcGIS} */ var GeocoderArcGIS = function () { function GeocoderArcGIS() { var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; _classCallCheck(this, GeocoderArcGIS); this.options = options; this.endpoint = this.options.endpoint || 'https://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/'; this.cache = {}; if (this.options.client_id && this.options.client_secret) { this.arcgisauth = new ArcGISAuth({ client_id: this.options.client_id, client_secret: this.options.client_secret }); } } /** * Geocode a string or object * * @param data string to be geocoded * @params {params} optional parameters * @return Promise */ _createClass(GeocoderArcGIS, [{ key: 'findAddressCandidates', value: function findAddressCandidates(data) { var params = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; return params.forStorage ? this._runAuth('findAddressCandidates', data, params) : this._run('findAddressCandidates', data, params); } /** * Geocode a string: Deprecated * For backwards compatibility only! * * @param data string to be geocoded * @params {params} optional parameters * @return Promise */ }, { key: 'geocode', value: function geocode(data) { var params = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; return params.forStorage ? this._runAuth('findAddressCandidates', data, params) : this._run('findAddressCandidates', data, params); } /** * Reverse geocode a LatLng * * @param data string to be reverse geocoded 'lat,lng' * @params {params} optional parameters * @return Promise */ }, { key: 'reverse', value: function reverse(data) { var params = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; return params.forStorage ? this._runAuth('reverseGeocode', data, params) : this._run('reverseGeocode', data, params); } /** * Make suggestion for a string * * @param data string to be geocoded * @params {params} optional parameters * @return Promise */ }, { key: 'suggest', value: function suggest(data) { var params = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; return this._run('suggest', data, params); } /** * Batch geocoding an array of addresses * * @param [data] array of addresses * @params {params} optional parameters * @return Promise */ }, { key: 'geocodeAddresses', value: function geocodeAddresses(data) { var params = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; return this._runAuth('geocodeAddresses', data, params); } /** * Generate the query for specific method */ }, { key: '_getQuery', value: function _getQuery(method, data, params) { var query = void 0; switch (method) { case 'find': query = this._getQueryGeocode(data, params);break; case 'reverseGeocode': query = this._getQueryReverse(data, params);break; case 'suggest': query = this._getQuerySuggest(data, params);break; case 'findAddressCandidates': query = this._getQueryFindAddressCandidates(data, params);break; case 'geocodeAddresses': query = this._getQueryGeocodeAddresses(data, params);break; } query.f = params.f || 'json'; query = Object.assign(params, query); return query; } /** * Prepare the query for find */ }, { key: '_getQueryGeocode', value: function _getQueryGeocode(data, params) { return { text: data, outFields: params.outFields || '*', maxLocations: params.maxLocations || 10 }; } /** * Prepare the query for reverse */ }, { key: '_getQueryReverse', value: function _getQueryReverse(data, params) { if (!this.validateLngLat(data)) return { error: 'LatLng wrong!' }; return { location: data, maxLocations: params.maxLocations || 10 }; } /** * Prepare the query for suggest */ }, { key: '_getQuerySuggest', value: function _getQuerySuggest(data, params) { return { text: data, outFields: params.outFields || '*', maxSuggestions: params.maxSuggestions || 10 }; } /** * Prepare the query for findAddressCandidates */ }, { key: '_getQueryFindAddressCandidates', value: function _getQueryFindAddressCandidates(data) { if (isString(data)) return { SingleLine: data }; if (isObject(data)) return data; } /** * Prepare the query for geocodeAddresses */ }, { key: '_getQueryGeocodeAddresses', value: function _getQueryGeocodeAddresses(data) { var records = []; data.forEach(function (address, index) { if (isString(address)) { records.push({ attributes: { OBJECTID: index, SingleLine: address } }); } else { // allow user to specify their own OBJECTIDs if (!address.OBJECTID) { address.OBJECTID = index; } records.push({ attributes: address }); } }); return { addresses: { records: records } }; } /** * Call the API w/out authentication * * @param method service method * @param data data * @params params optional parameters * @return promise */ }, { key: '_run', value: function _run(method, data, params) { var _this = this; return new Promise(function (resolve, reject) { var query = _this._getQuery(method, data, params); if (query.error) reject(query.error); _this._execute(_this.endpoint, method, query).then(resolve).catch(reject); }); } /** * Call the API w/ authentication * * @param method service method * @param data data * @params params optional parameters * @return promise */ }, { key: '_runAuth', value: function _runAuth(method, data, params) { var _this2 = this; if (!this.arcgisauth) throw new Error('Please specify client_id and client_secret!'); return new Promise(function (resolve, reject) { _this2.arcgisauth.auth().then(function (token) { var query = _this2._getQuery(method, data, params); query.token = token; if (query.error) reject(query.error); _this2._execute(_this2.endpoint, method, query).then(resolve).catch(reject); }).catch(reject); }); } /** * Sends a given request as a JSON object to the ArcGIS API and returns * a promise which if resolved will contain the resulting JSON object. * * @param {[type]} endpoint ArcGIS API endpoint to call * @param {[type]} params Object containg parameters to call the API with * @param {Function} Promise */ }, { key: '_execute', value: function _execute(endpoint, method, query) { var _this3 = this; return new Promise(function (resolve, reject) { var options = void 0; var url = void 0; if (method === 'geocodeAddresses') { // send geocodeAddresses with query as form data in HTTP POST request url = '' + endpoint + method; var formData = new FormData(); Object.keys(query).forEach(function (k) { var v = query[k]; formData.append(k, (typeof v === 'undefined' ? 'undefined' : _typeof(v)) === 'object' ? JSON.stringify(v) : v); }); options = { body: formData, method: 'POST' }; } else { // send all other requests using HTTP GET var params = _this3.getQueryString(query); url = '' + endpoint + method + '?' + params; options = { method: 'GET', qs: query }; } fetch(url, options).then(function (response) { if (response.status >= 400) reject({ code: 404, msg: 'Bad request to ' + url }); return response.json(); }).then(function (json) { resolve(json); }).catch(console.log); }); } }, { key: 'getQueryString', value: function getQueryString(params) { return Object.keys(params).map(function (k) { if (Array.isArray(params[k])) { return params[k].map(function (val) { return encodeURIComponent(k) + '[]=' + encodeURIComponent(val); }).join('&'); } return encodeURIComponent(k) + '=' + encodeURIComponent(params[k]); }).join('&'); } /** * Parsing error and return error object */ }, { key: 'parseError', value: function parseError(error) { if (error.code === 400 && error.details && error.details.length) { return { code: error.code, msg: get(error, 'details')[0] || 'Error' }; } return error; } /** * Validations */ }, { key: 'validateLngLat', value: function validateLngLat(lnglat) { var coordinates = lnglat.split(','); if (coordinates.length === 2) { var lat = Number(coordinates[1]); var lng = Number(coordinates[0]); if (lng > -180 && lng < 180 && lat > -90 && lat < 90) return true; } return; } }]); return GeocoderArcGIS; }(); module.exports = GeocoderArcGIS;