├── .editorconfig ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── data.js ├── index.html ├── index.js └── package.json /.editorconfig: -------------------------------------------------------------------------------- 1 | [*.js] 2 | indent_style = space 3 | indent_size = 2 4 | trim_trailing_whitespace = true 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | v1.1.1 2 | --- 3 | 4 | - Drop queue size argument [#10](https://github.com/mapbox/geocode-many/pull/10) 5 | 6 | v1.1.0 7 | --- 8 | 9 | - Upgrade packages and update query string to use Geocoder API v5 10 | 11 | v1.0.0 12 | --- 13 | 14 | - Update API endpoint to `v4`. Note: Requires an [access token](https://www.mapbox.com/help/create-api-access-token/) to be set. 15 | - Use https module for node support 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 2-Clause License 2 | 3 | Copyright (c) 2017, Mapbox 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | geocodemany 2 | --- 3 | 4 | Given an array of objects and a transform into a geocodable string, geocode 5 | them if possible. Works in both node and the browser. 6 | 7 | ### example 8 | 9 | ```js 10 | var data = [{ 11 | city: 'Chester', 12 | state: 'New Jersey' 13 | }, { 14 | city: 'Washington', 15 | state: 'DC' 16 | }]; 17 | 18 | function transform(obj) { 19 | return obj.city + ', ' + obj.state; 20 | } 21 | 22 | function progress() { 23 | console.log(arguments); 24 | } 25 | 26 | function done() { 27 | console.log(arguments); 28 | } 29 | 30 | var geocoder = geocodemany('ACCESSTOKEN'); 31 | 32 | geocoder(data, transform, progress, done); 33 | ``` 34 | -------------------------------------------------------------------------------- /data.js: -------------------------------------------------------------------------------- 1 | var data = [{ 2 | 'name': 'Birmingham' 3 | }, { 4 | 'name': 'Beijing' 5 | }, { 6 | 'name': 'Paris' 7 | }, { 8 | 'name': 'Tampa' 9 | }, { 10 | 'name': 'Leeds' 11 | }, { 12 | 'name': 'Rome' 13 | }, { 14 | 'name': 'Lagos' 15 | }, { 16 | 'name': 'Houston' 17 | }, { 18 | 'name': 'Stockholm' 19 | }, { 20 | 'name': 'Beijing' 21 | }, { 22 | 'name': 'Florence' 23 | }, { 24 | 'name': 'Vancouver' 25 | }, { 26 | 'name': 'Almaty, Kazakhstan' 27 | }, { 28 | 'name': 'Montreal' 29 | }, { 30 | 'name': 'Marseille' 31 | }, { 32 | 'name': 'Manchester' 33 | }, { 34 | 'name': 'Gdansk' 35 | }, { 36 | 'name': 'San Diego, Tijuana' 37 | }, { 38 | 'name': 'New Orleans' 39 | }, { 40 | 'name': 'Paris' 41 | }, { 42 | 'name': 'Kamloops' 43 | }, { 44 | 'name': 'Mexico City' 45 | }, { 46 | 'name': 'Paris' 47 | }, { 48 | 'name': 'Toronto' 49 | }, { 50 | 'name': 'Cincinnati' 51 | }, { 52 | 'name': 'Quito' 53 | }, { 54 | 'name': 'Columbus and Delaware, OH' 55 | }, { 56 | 'name': 'Vancouver' 57 | }, { 58 | 'name': 'Victoria' 59 | }, { 60 | 'name': 'Ankara' 61 | }, { 62 | 'name': 'Boston' 63 | }, { 64 | 'name': 'Prague' 65 | }, { 66 | 'name': 'Lille' 67 | }, { 68 | 'name': 'Cartagena de Indias' 69 | }, { 70 | 'name': 'New Orleans' 71 | }, { 72 | 'name': 'Kabul' 73 | }, { 74 | 'name': 'Brno' 75 | }, { 76 | 'name': 'Vancouver' 77 | }, { 78 | 'name': 'Shanghai' 79 | }, { 80 | 'name': 'Columbus and Delaware, OH' 81 | }, { 82 | 'name': 'Philadelphia' 83 | }, { 84 | 'name': 'Budapest' 85 | }, { 86 | 'name': 'Cairo' 87 | }, { 88 | 'name': 'Glasgow' 89 | }, { 90 | 'name': 'Los Angeles' 91 | }, { 92 | 'name': 'Cairo' 93 | }, { 94 | 'name': 'San Diego, Tijuana' 95 | }, { 96 | 'name': 'Beijing' 97 | }, { 98 | 'name': 'Sao Paulo' 99 | }, { 100 | 'name': 'Tehran' 101 | }, { 102 | 'name': 'Gdansk' 103 | }, { 104 | 'name': 'Miami' 105 | }, { 106 | 'name': 'Toronto' 107 | }, { 108 | 'name': 'Atlanta' 109 | }, { 110 | 'name': 'Munich' 111 | }, { 112 | 'name': 'Columbus and Delaware, OH' 113 | }, { 114 | 'name': 'Tokyo' 115 | }, { 116 | 'name': 'Johannesburg' 117 | }, { 118 | 'name': 'Phoenix' 119 | }, { 120 | 'name': 'Minneapolis, St. Paul' 121 | }, { 122 | 'name': 'New York City' 123 | }, { 124 | 'name': 'Damascus' 125 | }, { 126 | 'name': 'Montreal' 127 | }, { 128 | 'name': 'Leeds' 129 | }, { 130 | 'name': 'Brasília' 131 | }, { 132 | 'name': 'Madison' 133 | }, { 134 | 'name': 'Damascus' 135 | }, { 136 | 'name': 'New Orleans' 137 | }, { 138 | 'name': 'Glasgow' 139 | }, { 140 | 'name': 'Atlanta' 141 | }, { 142 | 'name': 'Austin' 143 | }, { 144 | 'name': 'Copenhagen' 145 | }, { 146 | 'name': 'Washington D.C., Baltimore' 147 | }, { 148 | 'name': 'Tampa' 149 | }, { 150 | 'name': 'Barcelona' 151 | }, { 152 | 'name': 'Austin' 153 | }, { 154 | 'name': 'Santiago' 155 | }, { 156 | 'name': 'Macon, GA' 157 | }, { 158 | 'name': 'Manila' 159 | }, { 160 | 'name': 'Kabul' 161 | }, { 162 | 'name': 'Lagos' 163 | }, { 164 | 'name': 'Buenos Aires' 165 | }, { 166 | 'name': 'Rome' 167 | }, { 168 | 'name': 'Miami' 169 | }, { 170 | 'name': 'Riyadh' 171 | }, { 172 | 'name': 'Austin' 173 | }, { 174 | 'name': 'Gdansk' 175 | }, { 176 | 'name': 'Ankara' 177 | }, { 178 | 'name': 'New Orleans' 179 | }, { 180 | 'name': 'Bangkok' 181 | }, { 182 | 'name': 'Berlin' 183 | }, { 184 | 'name': 'Johannesburg' 185 | }, { 186 | 'name': 'Auckland' 187 | }, { 188 | 'name': 'Mumbai' 189 | }, { 190 | 'name': 'Madison' 191 | }, { 192 | 'name': 'Leeds' 193 | }, { 194 | 'name': 'Moscow' 195 | }, { 196 | 'name': 'Lagos' 197 | }, { 198 | 'name': 'Riyadh' 199 | }]; 200 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 |View console.log for result
13 | 14 | 15 | 16 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var xhr = require('xhr'); 4 | var queue = require('d3-queue').queue; 5 | 6 | module.exports = geocodemany; 7 | 8 | function geocodemany(accessToken, throttle) { 9 | throttle = (throttle === undefined) ? 200 : throttle; 10 | return function(list, transform, progress, callback) { 11 | 12 | var q = queue(), 13 | todo = list.length, 14 | statuses = range(todo).map(function() { 15 | return undefined; 16 | }), 17 | done = 0; 18 | 19 | function range(n) { 20 | var arr = []; 21 | for (var i = 0; i < n; i++) arr.push(i); 22 | return arr; 23 | } 24 | 25 | function error(err, callback) { 26 | statuses[done] = false; 27 | progress({ 28 | todo: todo, 29 | done: ++done, 30 | status: 'error', 31 | statuses: statuses 32 | }); 33 | setTimeout(function() { 34 | callback(null, err); 35 | }, throttle); 36 | } 37 | 38 | // forgive me 39 | function copy(o) { 40 | return JSON.parse(JSON.stringify(o)); 41 | } 42 | 43 | function run(obj, callback) { 44 | var str = transform(obj); 45 | var output = copy(obj); 46 | 47 | var options = { 48 | uri: 'https://api.mapbox.com/geocoding/v5/mapbox.places/' + encodeURIComponent(str) + '.json?access_token=' + accessToken, 49 | method: 'GET', 50 | withCredentials: false 51 | }; 52 | 53 | xhr(options, function(err, res) { 54 | if (err) { 55 | error({ 56 | error: new Error('Location not found'), 57 | __iserror__: true, 58 | data: output 59 | }, callback); 60 | } 61 | 62 | var data = JSON.parse(res.body); 63 | if (data && data.features && data.features.length) { 64 | 65 | var ll = data.features[0]; 66 | output.longitude = ll.center[0]; 67 | output.latitude = ll.center[1]; 68 | statuses[done] = true; 69 | progress({ 70 | todo: todo, 71 | data: data ? data : {}, 72 | done: ++done, 73 | status: 'success', 74 | statuses: statuses 75 | }); 76 | setTimeout(function() { 77 | callback(null, output); 78 | }, throttle); 79 | 80 | } else { 81 | error({ 82 | error: new Error('Location not found'), 83 | __iserror__: true, 84 | data: output 85 | }, callback); 86 | } 87 | }); 88 | } 89 | 90 | function enqueue(obj) { 91 | q.defer(run, obj); 92 | } 93 | 94 | list.forEach(enqueue); 95 | 96 | q.awaitAll(function(err, res) { 97 | if (err) return callback(err); 98 | callback(res 99 | .filter(function(r) { 100 | return r.__iserror__; 101 | }) 102 | .map(function(r) { 103 | delete r.__iserror__; 104 | return r; 105 | }), 106 | res.filter(function(r) { 107 | return !r.__iserror__; 108 | })); 109 | }); 110 | }; 111 | } 112 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "license": "BSD-2-Clause", 3 | "name": "geocode-many", 4 | "repository": { 5 | "url": "git://github.com/mapbox/geocode-many.git", 6 | "type": "git" 7 | }, 8 | "author": "Mapbox", 9 | "bugs": { 10 | "url": "https://github.com/mapbox/geocode-many/issues" 11 | }, 12 | "version": "1.1.1", 13 | "dependencies": { 14 | "xhr": "^2.0.1", 15 | "d3-queue": "^3.0.3" 16 | }, 17 | "scripts": { 18 | "start": "budo index.js:geocodemany.js --live -- -s geocodemany", 19 | "build": "browserify index.js -s geocodemany | uglifyjs -c -m > geocodemany.js" 20 | }, 21 | "keywords": [ 22 | "geocode", 23 | "geo" 24 | ], 25 | "devDependencies": { 26 | "budo": "^9.2.0", 27 | "browserify": "^13.1.0" 28 | }, 29 | "main": "index.js", 30 | "homepage": "https://github.com/mapbox/geocode-many", 31 | "description": "Given an array of objects and a transform into a geocodable string, geocode them if possible." 32 | } --------------------------------------------------------------------------------