• Stars
    star
    178
  • Rank 214,989 (Top 5 %)
  • Language
    JavaScript
  • License
    Apache License 2.0
  • Created about 10 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Local reverse geocoder for Node.js based on GeoNames data

Local Reverse Geocoder

This library provides a local reverse geocoder for Node.js that is based on GeoNames data. It is local in the sense that there are no calls to a remote service like the Google Maps API, and in consequence the gecoder is suitable for batch reverse geocoding. It is reverse in the sense that you give it a (list of) point(s), i.e., a latitude/longitude pair, and it returns the closest city to that point.

Installation

$ npm install local-reverse-geocoder

Or, with Yarn:

$ yarn add local-reverse-geocoder

Docker

For usage with Docker, a Dockerfile is available in this project. It caches all the required files from GeoNames.

To build and run it:

$ docker build -t local-reverse-geocoder .
$ docker run -it -e PORT=3000 --rm local-reverse-geocoder

Or pull and run it:

$ docker run -it -e PORT=3000 --rm ghcr.io/tomayac/local-reverse-geocoder

Usage in Node.js

Init

You must initialize the geocoder prior to the first call to lookUp(). This ensures that all files are loaded into the cache prior to making the first call.

var geocoder = require('local-reverse-geocoder');

geocoder.init({}, function () {
  // geocoder is loaded and ready to run
});

Optionally init() also allows you to specify which files to load data from. This reduces initialization time and the runtime memory footprint of the Node.js process. By default all files are loaded.

var geocoder = require('local-reverse-geocoder');

geocoder.init(
  {
    citiesFileOverride: 'cities500', // one of 'cities500', 'cities1000', 'cities5000', 'cities15000' or null to keep the default city database (cities1000)
    load: {
      admin1: true,
      admin2: false,
      admin3And4: false,
      alternateNames: false,
    },
  },
  function () {
    // Ready to call lookUp
  }
);

Optionally init() allows you to specify the directory that geonames files are downloaded and cached in, and a specific cities database to be used.

var geocoder = require('local-reverse-geocoder');

geocoder.init({ dumpDirectory: '/tmp/geonames' }, function () {
  // Ready to call lookUp and all files will be downloaded to /tmp/geonames
});

Look Up

var geocoder = require('local-reverse-geocoder');

// With just one point
var point = { latitude: 42.083333, longitude: 3.1 };
geocoder.lookUp(point, function (err, res) {
  console.log(JSON.stringify(res, null, 2));
});

// In batch mode with many points
var points = [
  { latitude: 42.083333, longitude: 3.1 },
  { latitude: 48.466667, longitude: 9.133333 },
];
geocoder.lookUp(points, function (err, res) {
  console.log(JSON.stringify(res, null, 2));
});

// How many results to display at max
var maxResults = 5;

// With just one point
var point = { latitude: 42.083333, longitude: 3.1 };
geocoder.lookUp(point, maxResults, function (err, res) {
  console.log(JSON.stringify(res, null, 2));
});

// In batch mode with many points
var points = [
  { latitude: 42.083333, longitude: 3.1 },
  { latitude: 48.466667, longitude: 9.133333 },
];
geocoder.lookUp(points, maxResults, function (err, res) {
  console.log(JSON.stringify(res, null, 2));
});

Usage of the Web Service

You can use the built-in Web service by running node app.js as follows.

$ curl "http://localhost:3000/geocode?latitude=48.466667&longitude=9.133333&latitude=42.083333&longitude=3.1&maxResults=2"

Result Format

An output array that maps each point in the input array (or input object converted to a single-element array) to the maxResults closest addresses.

The measurement units are used as defined by GeoNames, for example, elevation is measured in meters. The distance value is dynamically calculated based on the haversine distance for the input point(s) to each of the particular results points and is measured in kilometers.

[
  [
    {
      geoNameId: '2919146',
      name: 'Gomaringen',
      asciiName: 'Gomaringen',
      alternateNames: null,
      latitude: '48.45349',
      longitude: '9.09582',
      featureClass: 'P',
      featureCode: 'PPLA4',
      countryCode: 'DE',
      cc2: null,
      admin1Code: {
        name: 'Baden-Württemberg',
        asciiName: 'Baden-Wuerttemberg',
        geoNameId: '2953481',
      },
      admin2Code: {
        name: 'Tübingen Region',
        asciiName: 'Tuebingen Region',
        geoNameId: '3214106',
      },
      admin3Code: {
        name: 'Landkreis Tübingen',
        asciiName: 'Landkreis Tubingen',
        geoNameId: '2820859',
      },
      admin4Code: {
        name: 'Gomaringen',
        asciiName: 'Gomaringen',
        geoNameId: '6555939',
      },
      population: '8400',
      elevation: null,
      dem: '430',
      timezone: 'Europe/Berlin',
      modificationDate: '2011-04-25',
      alternateName: {
        de: {
          altName: 'Gomaringen',
          isPreferredName: true,
          isShortName: false,
          isColloquial: false,
          isHistoric: false,
        },
      },
      distance: 3.1302317076079285,
    },
    {
      geoNameId: '2814195',
      name: 'Wannweil',
      asciiName: 'Wannweil',
      alternateNames: null,
      latitude: '48.51667',
      longitude: '9.15',
      featureClass: 'P',
      featureCode: 'PPLA4',
      countryCode: 'DE',
      cc2: null,
      admin1Code: {
        name: 'Baden-Württemberg',
        asciiName: 'Baden-Wuerttemberg',
        geoNameId: '2953481',
      },
      admin2Code: {
        name: 'Tübingen Region',
        asciiName: 'Tuebingen Region',
        geoNameId: '3214106',
      },
      admin3Code: {
        name: 'Landkreis Reutlingen',
        asciiName: 'Landkreis Reutlingen',
        geoNameId: '3220792',
      },
      admin4Code: {
        name: 'Wannweil',
        asciiName: 'Wannweil',
        geoNameId: '6555933',
      },
      population: '5092',
      elevation: null,
      dem: '320',
      timezone: 'Europe/Berlin',
      modificationDate: '2011-04-25',
      distance: 5.694122211376861,
    },
  ],
  [
    {
      geoNameId: '3130634',
      name: 'Albons',
      asciiName: 'Albons',
      alternateNames: null,
      latitude: '42.10389',
      longitude: '3.08433',
      featureClass: 'P',
      featureCode: 'PPLA3',
      countryCode: 'ES',
      cc2: null,
      admin1Code: {
        name: 'Catalonia',
        asciiName: 'Catalonia',
        geoNameId: '3336901',
      },
      admin2Code: {
        name: 'Província de Girona',
        asciiName: 'Provincia de Girona',
        geoNameId: '6355230',
      },
      admin3Code: {
        name: 'Albons',
        asciiName: 'Albons',
        geoNameId: '6534005',
      },
      admin4Code: null,
      population: '558',
      elevation: '13',
      dem: '18',
      timezone: 'Europe/Madrid',
      modificationDate: '2012-03-04',
      distance: 2.626176210836868,
    },
    {
      geoNameId: '3118799',
      name: "la Tallada d'Empordà",
      asciiName: "la Tallada d'Emporda",
      alternateNames:
        "La Tallada,la Tallada,la Tallada d'Emporda,la Tallada d'Empordà",
      latitude: '42.0802',
      longitude: '3.05583',
      featureClass: 'P',
      featureCode: 'PPLA3',
      countryCode: 'ES',
      cc2: null,
      admin1Code: {
        name: 'Catalonia',
        asciiName: 'Catalonia',
        geoNameId: '3336901',
      },
      admin2Code: {
        name: 'Província de Girona',
        asciiName: 'Provincia de Girona',
        geoNameId: '6355230',
      },
      admin3Code: {
        name: "la Tallada d'Empordà",
        asciiName: "la Tallada d'Emporda",
        geoNameId: '6534150',
      },
      admin4Code: null,
      population: '0',
      elevation: null,
      dem: '16',
      timezone: 'Europe/Madrid',
      modificationDate: '2012-03-04',
      distance: 3.6618561653699846,
    },
  ],
];

A Word on Accuracy

By design, i.e., due to the granularity of the available GeoNames data, this reverse geocoder is limited to city-level, so no streets or house numbers. In many cases this is already sufficient, but obviously your actual mileage may vary. If you need street-level granularity, you are better off with a service like Google's reverse geocoding API. (Full disclosure: the author is currently employed by Google.)

A Word on Initialization Speed

The initial lookup takes quite a while, as the geocoder has to download roughly 2GB(!) of data that it then caches locally (unzipped, this occupies about 1.3GB of disk space). All follow-up requests are lightning fast.

Downloading specific sets of countries

To reduce the time taken to initialize the data, you can manually configure it to only download a specific set of countries from Geonames. Do note that when you add a country code into the array, it will disable the geocoder from downloading all ~2GB(!) worth of data and only load the specified countries' data. If you want to re-enable the geocoder to download all data, the countries array needs to be empty.

Example of getting data for individual country

const geocoder = require('local-reverse-geocoder');
geocoder.init(
  {
    load: {
      admin1: true,
      admin2: true,
      admin3And4: true,
      alternateNames: true,
    },
    // Comma-separated list of country codes. An empty array means all countries.
    countries: ['SG', 'AU'],
  },
  function () {
    // Ready to call lookUp
  }
);

Post-install script

There's also the option of downloading the Geonames files via a post-install script.
The script is invoked automatically after installation, but won't download any files without getting at least one of the init options in an env variable.
The options should be specified with a GEOCODER_POSTINSTALL_ prefix.

Example of downloading the files via the post-install script

export GEOCODER_POSTINSTALL_DUMP_DIRECTORY=/usr/src/app
export GEOCODER_POSTINSTALL_ADMIN1=true
export GEOCODER_POSTINSTALL_ADMIN2=true
export GEOCODER_POSTINSTALL_COUNTRIES=SG,AU
npm install local-reverse-geocoder

// As long as the app is started within the same day
// and uses the same options, the init call won't download any files.

A Word on Data Freshness

By default, the local GeoNames dump data gets refreshed each day. You can override this behavior by removing the timestamp from the files in the ./geonames_dump download folder. If you don't need admin1, admin2, admin3, admin4 or alternate names you can turn them off in a manual init call and decrease load time.

A Word on Memory Usage

If you run into a FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory issue, try running node with the V8 option --max-old-space-size=2000.

A Word on Debugging

To turn on debug logging add a DEBUG=local-reverse-geocoder environment variable on the command line.

License

Copyright 2017 Thomas Steiner ([email protected])

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

Acknowledgements

This project was inspired by Richard Penman's Python reverse geocoder. It uses Ubilabs' k-d-tree implementation that was ported to Node.js by Luke Arduini.

Contributors

npm

More Repositories

1

SVGcode

Convert color bitmap images to color SVG vector images.
JavaScript
744
star
2

dark-mode-email

This repo shows how to create emails that support dark mode.
JavaScript
155
star
3

wikipedia-tools-for-google-spreadsheets

Wikipedia Tools for Google Spreadsheets — Install:
JavaScript
132
star
4

pwa-feature-detector

Progressive Web App 🕵️ Feature Detector
HTML
109
star
5

joy-con-webhid

Use the Nintendo Switch Joy-Cons via the WebHID API
JavaScript
108
star
6

opfs-explorer

OPFS Explorer is a Chrome DevTools extension that allows you to explore the Origin Private File System (OPFS) of a web application.
JavaScript
88
star
7

fetch-in-chunks

A utility for fetching large files in chunks with support for parallel downloads and progress tracking.
JavaScript
87
star
8

esm-potrace-wasm

A modern ESM build of the Potrace library for use in the browser.
C
70
star
9

fugu-greetings

A sample app that features a lot of Project Fugu 🐡 APIs.
JavaScript
62
star
10

dark-mode-screenshot

This Puppeteer script takes a 📷 screenshot of a webpage in 🌞 Light and 🌒 Dark Mode.
JavaScript
56
star
11

wikipedia-irc

Try to spot new trends based on Wikipedia live edit spikes
JavaScript
50
star
12

Media-Fragments-URI

Media Fragments URI is a W3C specification with the objective to provide for media-format independent, standard means of addressing media fragments on the Web using Uniform Resource Identifiers (URIs).
JavaScript
43
star
13

js-input-masking

39
star
14

xywh.js

xywh.js is a JavaScript polyfill that lets you crop images and videos simply by using specific x, y, width, and height information from their URIs (see mark-up examples below).The library implements the spatial media fragments dimension of the W3C Media Fragments URI specification as a polyfill. Please refer to http://www.w3.org/TR/media-frags/#naming-space for the full details.
JavaScript
25
star
15

pageviews.js

A lightweight JavaScript client library for the Wikimedia Pageviews API for Wikipedia and various of its sister projects for Node.js and the browser.
JavaScript
24
star
16

wikipedia-live-monitor

JavaScript
19
star
17

ldf-client

Polymer Linked Data Fragments client
HTML
17
star
18

pwa-workshop

Exemplary Progressive Web App (PWA) that showcases PWA features like offline support, push notifications, and add to homescreen.
HTML
15
star
19

chrome-dino-webhid

Play chrome://dino 🦖 via WebHID using your Joy-Cons 🎮
JavaScript
13
star
20

hiit-time

HIIT time app
TypeScript
12
star
21

chrome-dino-gamepad

Play chrome://dino 🦖 with your gamepad 🎮
JavaScript
12
star
22

wasmoptim

Optimize your WebAssembly files
JavaScript
12
star
23

prompt-api-playground

This is a demo of Chrome's built-in Prompt API powered by Gemini Nano.
JavaScript
11
star
24

sqlite3-wasm-demo

JavaScript
11
star
25

babelnet_js

JavaScript wrapper for BabelNet™
JavaScript
11
star
26

link-to-media

JavaScript
11
star
27

wikipedia-around

📍 Wikipedia Around shows you Wikipedia articles that describe places, events, or points of interest that are near you.
JavaScript
10
star
28

html5-slides

HTML5 slide deck originally based on https://code.google.com/p/io-2012-slides
JavaScript
10
star
29

js-input-masking-polyfill

Polyfill for the Intl.InputMask proposal.
JavaScript
9
star
30

how-fugu-is-the-web

An extension to shine light on the Project Fugu 🐡 APIs web apps want to use.
JavaScript
9
star
31

io22-samples

HTML
8
star
32

fugu-paint

JavaScript
8
star
33

blogccasion

The new Blogccasion
HTML
7
star
34

affilicats-microsites

HTML
7
star
35

hyper-video

Polymer Hypervideo Web Component
HTML
7
star
36

isearch

I-SEARCH GUI
JavaScript
7
star
37

phd

Thomas Steiner's PhD Thesis
TeX
7
star
38

language-identifier

N-gram-based JavaScript language identification
JavaScript
7
star
39

amp-tube

A simple YouTube search engine and viewer app, implemented in AMP
7
star
40

postdoc

TeX
6
star
41

sqlite-wiki

JavaScript
6
star
42

delayedgram

Delayedgram
JavaScript
6
star
43

font-select

Custom element for picking local fonts
JavaScript
6
star
44

http-archive-progressive-web-apps

Different approaches to estimate the number of Progressive Web Apps in the HTTP Archive
5
star
45

adwords-scripts-reporting

AdWords Scripts Reporting
JavaScript
5
star
46

rest-describe-and-compile

REST Describe & Compile
Java
5
star
47

fugu-showcase

Fugu API Showcase
HTML
5
star
48

fugu-api-data

This repo contains raw data for Project Fugu 🐡 APIs.
JavaScript
4
star
49

own-window

A custom element to make sure demos run in their own window and not embedded as an iframe.
JavaScript
3
star
50

althttpd-wasm

A WebAssembly version of althttpd, a simple web server written in C.
C
3
star
51

confetti-popper

JavaScript
3
star
52

the-capable-web

TeX
3
star
53

dhbw-pwa-tutorial

DHBW PWA Tutorial
JavaScript
3
star
54

how-fugu-is-my-browser

A test app to determine what Project Fugu 🐡 APIs your browser supports.
JavaScript
3
star
55

media-server

JavaScript
3
star
56

wasm-bundling

3
star
57

apps-scripts-adwords-scripts-jshintrc-jscsrc

A JSHint configuration for use with Google Apps Script
JavaScript
3
star
58

web-directions-code

Web Directions Code conference badge
JavaScript
3
star
59

wikipedia-edits-server-sent-events

This project emits a Server-Sent Event (SSE) upon each Wikipedia edit
JavaScript
3
star
60

multimedia-algorithms

JavaScript
3
star
61

oculus-pwa-test

Oculus PWA Test
HTML
2
star
62

eswc2012

2
star
63

codetalks-pwa

code.talks Conference Demo Progressive Web App (PWA) — https://tomayac.github.io/codetalks-pwa/programm.html
HTML
2
star
64

_Private-Paper-MSM2011

Internal use only.
2
star
65

business-cards

Business Cards
JavaScript
2
star
66

whats-in-a-web-view

What is in a Web View? An Analysis of Progressive Web App Features When the Means of Web Access is not a Web Browser
TeX
2
star
67

I-SEARCH

JavaScript
2
star
68

swj-microposts

JavaScript
2
star
69

enphase-solar

JavaScript
2
star
70

api-screenshot

JavaScript
2
star
71

Breadcrumb-Navigator-Theming-Kit

Breadcrumb Navigator Theming Kit is intended for users of the Google Chrome Breadcrumb Navigator extension who want to create their own themes.
HTML
2
star
72

wakelock-thereami

JavaScript
2
star
73

fdfdsf

JavaScript
2
star
74

toward-making-opaque-web-content-more-accessible

TeX
2
star
75

wakelock-whereami

JavaScript
1
star
76

SDOW2011

1
star
77

news-pwa

News Progressive Web App
JavaScript
1
star
78

acmmm2012grandchallenge

ACMMM 2012 Grand Challenge
JavaScript
1
star
79

translation-language-detection-api-playground

HTML
1
star
80

Linked-Data-API

This project provides a very early alpha stage implementation of the W3C RDFa API
JavaScript
1
star
81

_Private-LD4WD-Chapter2-Code

Internal use only.
JavaScript
1
star
82

.well-known

1
star
83

fugu-hashtags

JavaScript
1
star
84

cross-platform-software-frameworks

1
star
85

window-placement-keyboard-lock

HTML
1
star
86

joy-con-webhid-paper

TeX
1
star
87

origin-trials

JavaScript
1
star
88

wikipedia-screensaver

Wikipedia Screensaver
JavaScript
1
star
89

adwords-reports-nodejs-lib

The project adwords-reports-nodejs-lib provides a simple AdWords reporting library for pulling ad hoc reports described in the AdWords Query Lanaguage (AWQL) directly from the AdWords API.
JavaScript
1
star
90

tomayac.github.io

HTML
1
star
91

iswc2012

PHP
1
star
92

primary-sources-tool-paper

Repository for the WWW 2016 Industry Track Paper "From Freebase to Wikidata: The Great Migration"
TeX
1
star
93

user-preference-media-features-headers

HTML
1
star