1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136 | 2x
2x
2x
7x
6x
6x
6x
2x
10x
10x
10x
10x
10x
10x
10x
10x
10x
2x
2x
2x
2x
2x
2x
1x
1x
1x
1x
1x
1x
1x
1x
1x
2x
2x
2x
2x
2x
2x
2x
2x
1x
2x
1x
2x
2x
1x
1x
1x
1x
1x
1x
1x
1x
1x
1x
1x
1x
1x
1x
1x
1x
1x
2x
| var util = require('util');
var AbstractGeocoder = require('./abstractgeocoder');
/**
* Constructor
*/
var TeleportGeocoder = function TeleportGeocoder(httpAdapter, options) {
TeleportGeocoder.super_.call(this, httpAdapter, options);
var base = 'https://api.teleport.org/api';
this._cities_endpoint = base + '/cities/';
this._locations_endpoint = base + '/locations/';
};
util.inherits(TeleportGeocoder, AbstractGeocoder);
function getEmbeddedPath(parent, path) {
var elements = path.split('/');
for ( var i in elements) {
var element = elements[i];
var embedded = parent._embedded;
Iif (!embedded) {
return undefined;
}
var child = embedded[element];
Iif (!child) {
return undefined;
}
parent = child;
}
return parent;
}
/**
* Geocode
*
* @param <string> value Value to geocode (Address)
* @param <function> callback Callback method
*/
TeleportGeocoder.prototype._geocode = function(value, callback) {
var _this = this;
var params = {};
params.search = value;
params.embed = 'city:search-results/city:item/{city:country,city:admin1_division,city:urban_area}';
this.httpAdapter.get(this._cities_endpoint, params, function(err, result) {
Iif (err) {
return callback(err);
} else {
var results = [];
Eif (result) {
var searchResults = getEmbeddedPath(result, 'city:search-results') || [];
for (var i in searchResults) {
var confidence = (25 - i) / 25.0 * 10;
results.push(_this._formatResult(searchResults[i], 'city:item', confidence));
}
}
results.raw = result;
callback(false, results);
}
});
};
TeleportGeocoder.prototype._formatResult = function(result, cityRelationName, confidence) {
var city = getEmbeddedPath(result, cityRelationName);
var admin1 = getEmbeddedPath(city, 'city:admin1_division') || {};
var country = getEmbeddedPath(city, 'city:country') || {};
var urban_area = getEmbeddedPath(city, 'city:urban_area') || {};
var urban_area_links = urban_area._links || {};
var extra = {
confidence: confidence,
urban_area: urban_area.name,
urban_area_api_url: (urban_area_links.self || {}).href,
urban_area_web_url: urban_area.teleport_city_url
};
if (result.distance_km) {
extra.distance_km = result.distance_km;
}
if (result.matching_full_name) {
extra.matching_full_name = result.matching_full_name;
}
return {
'latitude': city.location.latlon.latitude,
'longitude': city.location.latlon.longitude,
'city': city.name,
'country': country.name,
'countryCode': country.iso_alpha2,
'state': admin1.name,
'stateCode': admin1.geonames_admin1_code,
'extra': extra
};
};
/**
* Reverse geocoding
*
* @param {lat:<number>,lon:<number>} lat: Latitude, lon: Longitude
* @param <function> callback Callback method
*/
TeleportGeocoder.prototype._reverse = function(query, callback) {
var lat = query.lat;
var lng = query.lon;
var suffix = lat + ',' + lng;
var _this = this;
var params = {};
params.embed = 'location:nearest-cities/location:nearest-city/{city:country,city:admin1_division,city:urban_area}';
this.httpAdapter.get(this._locations_endpoint + suffix, params, function(err, result) {
Iif (err) {
throw err;
} else {
var results = [];
Eif (result) {
var searchResults = getEmbeddedPath(result, 'location:nearest-cities') || [];
for ( var i in searchResults) {
var searchResult = searchResults[i];
var confidence = Math.max(0, 25 - searchResult.distance_km) / 25 * 10;
results.push(_this._formatResult(searchResult, 'location:nearest-city', confidence));
}
}
results.raw = result;
callback(false, results);
}
});
};
module.exports = TeleportGeocoder;
|