UNPKG

@webkitty/geo-rev

Version:

Reverse geocoder for Node.js working with offline data and fast lookup times.

93 lines 3.25 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __exportStar = (this && this.__exportStar) || function(m, exports) { for (var p in m) if (p !== "default" && !exports.hasOwnProperty(p)) __createBinding(exports, m, p); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.RevGeocoder = exports.createRevGeocoder = void 0; const fs_1 = require("fs"); const path_1 = require("path"); const readline_1 = require("readline"); const events_1 = require("events"); const createKDTree = require("static-kdtree"); __exportStar(require("./types"), exports); async function createRevGeocoder(options) { return new RevGeocoder(options).init(); } exports.createRevGeocoder = createRevGeocoder; class RevGeocoder { constructor(options) { this.records = []; options = options || {}; options.dataset = options.dataset || path_1.join(__dirname, '..', 'data', 'cities500.csv'); this.dataset = options.dataset; } async init() { this.records = await parseDataset(this.dataset); this.index = createIndex(this.records); return this; } lookup(point) { if (!this.index) { throw new Error('Index not initialized.'); } const nearestRecordIndex = this.index.nn([point.latitude, point.longitude]); if (nearestRecordIndex < 0 || nearestRecordIndex >= this.records.length) { throw new Error('Record index out of bounds.'); } return { record: this.records[nearestRecordIndex], distance: distanceBetween(point, this.records[nearestRecordIndex]), }; } } exports.RevGeocoder = RevGeocoder; async function parseDataset(dataset) { const records = []; const reader = readline_1.createInterface({ input: fs_1.createReadStream(dataset), historySize: 0, crlfDelay: Infinity, }); reader.on('line', line => records.push(parseLine(line))); await events_1.once(reader, 'close'); return records; } function parseLine(line) { const cols = line.split(';'); return { name: cols[0], latitude: parseFloat(cols[1]), longitude: parseFloat(cols[2]), countryCode: cols[3], }; } function createIndex(records) { return createKDTree(records.map(record => [record.latitude, record.longitude])); } function distanceBetween(x, y) { const lat1 = x.latitude; const lon1 = x.longitude; const lat2 = y.latitude; const lon2 = y.longitude; const R = 6371; const φ1 = toRad(lat1); const φ2 = toRad(lat2); const Δφ = toRad(lat2 - lat1); const Δλ = toRad(lon2 - lon1); const a = Math.sin(Δφ / 2) * Math.sin(Δφ / 2) + Math.cos1) * Math.cos2) * Math.sin(Δλ / 2) * Math.sin(Δλ / 2); const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); return R * c; } function toRad(deg) { return deg * Math.PI / 180; } //# sourceMappingURL=index.js.map